diff --git a/.editorconfig b/.editorconfig index c6c8b3621..f6d83b7c7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,3 +7,11 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true + +[*.rs] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/workflows/ci-stable.yml b/.github/workflows/ci-stable.yml deleted file mode 100644 index 80d19dca0..000000000 --- a/.github/workflows/ci-stable.yml +++ /dev/null @@ -1,59 +0,0 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: CI — Stable - -on: - push: - branches: [master] - pull_request: - branches: [master, 3.3] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14, 18] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: | - npm run test || \ - npm run test || \ - npm run test || exit 1 - - - name: Lint - run: npm run style diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e2433d3b..0241a67b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,10 @@ -name: CI — Oxide +name: CI on: push: - branches: [master, 3.3] + branches: [master] pull_request: - branches: [master, 3.3] + branches: [master] permissions: contents: read @@ -13,7 +13,6 @@ env: CI: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: oxide jobs: build: @@ -34,7 +33,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo @@ -62,14 +61,36 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npx turbo run build --filter=// - - name: Test + - name: Test (Node.js) run: | npx turbo run test --filter=// || \ npx turbo run test --filter=// || \ npx turbo run test --filter=// || exit 1 + - name: Test (Rust) + run: | + cd ./oxide + cargo test || \ + cargo test || \ + cargo test || exit 1 + cd - + - name: Lint run: npx turbo run style --filter=// diff --git a/.github/workflows/integration-tests-stable.yml b/.github/workflows/integration-tests-stable.yml deleted file mode 100644 index b28207196..000000000 --- a/.github/workflows/integration-tests-stable.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Integration Tests — Stable - -on: - push: - branches: [master, 3.3] - pull_request: - branches: [master, 3.3] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - -jobs: - test: - runs-on: ubuntu-latest - - strategy: - matrix: - integration: - - content-resolution - - parcel - - postcss-cli - - rollup - - rollup-sass - - tailwindcss-cli - - vite - - webpack-4 - - webpack-5 - node-version: [18] - fail-fast: false - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules (tailwindcss) - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('package-lock.json') }} - - - name: Cache node_modules (integrations) - uses: actions/cache@v3 - with: - path: ./integrations/node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-integrations-${{ hashFiles('./integrations/package-lock.json') }} - - - name: Cache node_modules (integration) - uses: actions/cache@v3 - with: - path: ./integrations/${{ matrix.integration }}/node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-integrations-${{ matrix.integration }}-${{ hashFiles('./integrations/${{ matrix.integration }}/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Install dependencies (shared integrations) - run: npm install --prefix ./integrations - - - name: Install dependencies (integration) - run: npm install --prefix ./integrations/${{ matrix.integration }} - - - name: Build Tailwind CSS - run: npm run build - - - name: Test ${{ matrix.integration }} - run: | - npm run test --prefix ./integrations/${{ matrix.integration }} || \ - npm run test --prefix ./integrations/${{ matrix.integration }} || \ - npm run test --prefix ./integrations/${{ matrix.integration }} || exit 1 diff --git a/.github/workflows/integration-tests-oxide.yml b/.github/workflows/integration-tests.yml similarity index 78% rename from .github/workflows/integration-tests-oxide.yml rename to .github/workflows/integration-tests.yml index 9da82b4b8..3fd0f3f33 100644 --- a/.github/workflows/integration-tests-oxide.yml +++ b/.github/workflows/integration-tests.yml @@ -1,10 +1,10 @@ -name: Integration Tests — Oxide +name: Integration Tests on: push: - branches: [master, 3.3] + branches: [master] pull_request: - branches: [master, 3.3] + branches: [master] permissions: contents: read @@ -13,7 +13,6 @@ env: CI: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: oxide jobs: test: @@ -46,7 +45,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo @@ -74,6 +73,20 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npx turbo run build --filter=// diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 2ad36d3dd..af5ef0be7 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -53,6 +53,20 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npm run build diff --git a/.github/workflows/release-insiders-stable.yml b/.github/workflows/release-insiders-stable.yml deleted file mode 100644 index f8bb322d4..000000000 --- a/.github/workflows/release-insiders-stable.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Release Insiders — Stable - -on: - push: - branches: [master] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - NODE_VERSION: 16 - RELEASE_CHANNEL: insiders - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - registry-url: 'https://registry.npmjs.org' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: | - npm run test || \ - npm run test || \ - npm run test || exit 1 - - - name: Resolve version - id: vars - run: | - echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - - name: 'Version based on commit: 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}' - run: npm version 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }} --force --no-git-tag-version - - - name: Publish - run: npm publish --tag ${{ env.RELEASE_CHANNEL }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Trigger Tailwind Play update - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tailwindlabs', - repo: 'play.tailwindcss.com', - ref: 'master', - workflow_id: 'upgrade-tailwindcss.yml', - inputs: { - insidersVersion: '0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}' - } - }) diff --git a/.github/workflows/release-insiders-oxide.yml b/.github/workflows/release-insiders.yml similarity index 97% rename from .github/workflows/release-insiders-oxide.yml rename to .github/workflows/release-insiders.yml index 4130349ba..d6eb24606 100644 --- a/.github/workflows/release-insiders-oxide.yml +++ b/.github/workflows/release-insiders.yml @@ -1,4 +1,4 @@ -name: Release Insiders — Oxide +name: Release Insiders on: push: @@ -8,7 +8,7 @@ env: APP_NAME: tailwindcss-oxide NODE_VERSION: 16 OXIDE_LOCATION: ./oxide/crates/node - RELEASE_CHANNEL: oxide-insiders + RELEASE_CHANNEL: insiders jobs: build: @@ -170,15 +170,13 @@ jobs: include: - target: x86_64-unknown-linux-gnu strip: strip - image: docker.io/centos/nodejs-14-centos7 + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - target: aarch64-unknown-linux-musl image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine strip: aarch64-linux-musl-strip @@ -353,7 +351,7 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - tailwind_oxide_release: + tailwind-release: runs-on: ubuntu-latest name: Build and release Tailwind CSS diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml deleted file mode 100644 index 23a3f2dc0..000000000 --- a/.github/workflows/release-stable.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Release — Stable - -on: - release: - types: [published] - -permissions: - contents: read - -env: - CI: true - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14] - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - registry-url: 'https://registry.npmjs.org' - cache: 'npm' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: npm run test - - - name: Calculate environment variables - run: | - echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV - echo "TAILWINDCSS_VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - - - name: Publish - run: npm publish --tag ${{ env.RELEASE_CHANNEL }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Trigger Tailwind Play update - if: env.RELEASE_CHANNEL == 'latest' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tailwindlabs', - repo: 'play.tailwindcss.com', - ref: 'master', - workflow_id: 'upgrade-tailwindcss.yml', - inputs: { - version: '${{ env.TAILWINDCSS_VERSION }}' - } - }) diff --git a/.github/workflows/release-oxide.yml b/.github/workflows/release.yml similarity index 50% rename from .github/workflows/release-oxide.yml rename to .github/workflows/release.yml index ad71ec657..5c9da43c5 100644 --- a/.github/workflows/release-oxide.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,19 @@ -name: Release — Oxide +name: Release on: - workflow_dispatch: + release: + types: [published] + +permissions: + contents: read env: APP_NAME: tailwindcss-oxide - NODE_VERSION: 14 + NODE_VERSION: 16 OXIDE_LOCATION: ./oxide/crates/node jobs: - oxide-build: + build: strategy: fail-fast: false matrix: @@ -27,6 +31,35 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + - name: Install Node.JS uses: actions/setup-node@v3 with: @@ -42,18 +75,8 @@ jobs: - name: Setup rust target run: rustup target add ${{ matrix.target }} - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-${{ matrix.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- - - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + - name: Install dependencies + run: npm install - name: Build release run: cd ${{ env.OXIDE_LOCATION }} && npm run build @@ -72,7 +95,7 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ matrix.binary }} - oxide-build-apple-silicon: + build-apple-silicon: name: Build Apple Silicon (OXIDE) runs-on: macos-latest steps: @@ -82,7 +105,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo @@ -94,7 +117,18 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('./oxide/**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} - name: Install Node.JS uses: actions/setup-node@v3 @@ -131,22 +165,20 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ env.APP_NAME }} - oxide-build-linux: + build-linux: strategy: fail-fast: false matrix: include: - target: x86_64-unknown-linux-gnu strip: strip - image: docker.io/centos/nodejs-14-centos7 + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - target: aarch64-unknown-linux-musl image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine strip: aarch64-linux-musl-strip @@ -162,6 +194,35 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + - name: Install Node.JS uses: actions/setup-node@v3 with: @@ -181,18 +242,8 @@ jobs: - name: Setup rust target run: rustup target add ${{ matrix.target }} - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-linux-${{ matrix.target }}-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- - - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + - name: Install dependencies + run: npm install - name: Build release run: cd ${{ env.OXIDE_LOCATION }} && npm run build @@ -211,28 +262,52 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ env.APP_NAME }} - oxide-release: + release: runs-on: ubuntu-latest name: Build and release needs: - - oxide-build - - oxide-build-linux - - oxide-build-apple-silicon + - build + - build-linux + - build-apple-silicon steps: - uses: actions/checkout@v3 - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-ubuntu-latest-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + + - name: Install dependencies + run: npm install + + - name: Calculate environment variables + run: | + echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV + echo "VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - name: Download artifacts uses: actions/download-artifact@v3 @@ -255,11 +330,6 @@ jobs: cp bindings-x86_64-unknown-linux-gnu/oxide/crates/node/* ./npm/linux-x64-gnu/ cp bindings-x86_64-unknown-linux-musl/oxide/crates/node/* ./npm/linux-x64-musl/ - - name: Resolve version - id: vars - run: | - echo "NPM_VERSION=0.0.0-insiders.$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - name: Generate entry point run: npm run build --prefix ${{ env.OXIDE_LOCATION }} @@ -268,50 +338,74 @@ jobs: for pkg in ${{ env.OXIDE_LOCATION }}/npm/*; do echo "Publishing $pkg..." cd $pkg - npm version ${{ env.NPM_VERSION }} --force --no-git-tag-version - npm publish --tag insiders --access public + npm version ${{ env.VERSION }} --force --no-git-tag-version + npm publish --tag ${{ env.RELEASE_CHANNEL }} --access public cd - done echo "Publishing ${{ env.APP_NAME }}..."; cd ${{ env.OXIDE_LOCATION }} - npm version ${{ env.NPM_VERSION }} --force --no-git-tag-version - sed "s#\"0.0.0\"#\"${{ env.NPM_VERSION }}\"#g" package.json > package_updated.json + npm version ${{ env.VERSION }} --force --no-git-tag-version + sed "s#\"0.0.0\"#\"${{ env.VERSION }}\"#g" package.json > package_updated.json mv package_updated.json package.json - npm publish --tag insiders --access public + npm publish --tag ${{ env.RELEASE_CHANNEL }} --access public cd - env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - tailwind_oxide_release: + tailwind-release: runs-on: ubuntu-latest name: Build and release Tailwind CSS needs: - - oxide-release - - strategy: - matrix: - node-version: [14] + - release steps: - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + + - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ env.NODE_VERSION }} registry-url: 'https://registry.npmjs.org' - - name: Resolve version - id: vars + - name: Calculate environment variables run: | - echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - echo "OXIDE_NPM_VERSION=0.0.0-insiders.$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV + echo "VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - name: Setup `@tailwindcss/oxide` version run: | - sed "s#\"@tailwindcss/oxide\": \".*\"#\"@tailwindcss/oxide\": \"${{ env.OXIDE_NPM_VERSION }}\"#" package.json > package_updated.json + sed "s#\"@tailwindcss/oxide\": \".*\"#\"@tailwindcss/oxide\": \"${{ env.VERSION }}\"#" package.json > package_updated.json mv package_updated.json package.json - name: Install dependencies @@ -321,12 +415,31 @@ jobs: run: npm run build - name: Test - run: npm test + run: | + npm test || \ + npm test || \ + npm test || exit 1 - - name: 'Version based on commit: 0.0.0-oxide.${{ env.SHA_SHORT }}' - run: npm version 0.0.0-oxide.${{ env.SHA_SHORT }} --force --no-git-tag-version + - name: 'Version: ${{ env.VERSION }}' + run: npm version ${{ env.VERSION }} --force --no-git-tag-version - name: Publish - run: npm publish --tag oxide + run: npm publish --tag ${{ env.RELEASE_CHANNEL }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # - name: Trigger Tailwind Play update + # if: env.RELEASE_CHANNEL == 'latest' + # uses: actions/github-script@v6 + # with: + # github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} + # script: | + # await github.rest.actions.createWorkflowDispatch({ + # owner: 'tailwindlabs', + # repo: 'play.tailwindcss.com', + # ref: 'master', + # workflow_id: 'upgrade-tailwindcss.yml', + # inputs: { + # version: '${{ env.TAILWINDCSS_VERSION }}' + # } + # }) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd899dc53..324c161c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) +- Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) +- Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) +- Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) +- Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) +- Fix source maps issue resulting in a crash ([#11319](https://github.com/tailwindlabs/tailwindcss/pull/11319)) +- Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335)) +- Move unknown pseudo-elements outside of `:is` by default ([#11345](https://github.com/tailwindlabs/tailwindcss/pull/11345)) + +### Added + +- Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) +- Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205), ([#11260](https://github.com/tailwindlabs/tailwindcss/pull/11260))) +- Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) +- Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) +- Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) +- Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) +- Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) +- Add `text-wrap` utilities including `text-balance` ([#11320](https://github.com/tailwindlabs/tailwindcss/pull/11320)) +- Explicitly configure Lightning CSS features, and prefer user browserslist over default browserslist ([#11402](https://github.com/tailwindlabs/tailwindcss/pull/11402), [#11412](https://github.com/tailwindlabs/tailwindcss/pull/11412)) + +### Changed + +- Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) +- Deprecate `--no-autoprefixer` flag in the CLI ([#11280](https://github.com/tailwindlabs/tailwindcss/pull/11280)) +- Make the Rust based parser the default ([#11394](https://github.com/tailwindlabs/tailwindcss/pull/11394)) ## [3.3.2] - 2023-04-25 diff --git a/README.md b/README.md index 17663787f..625b83ad5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

- Build Status + Build Status Total Downloads Latest Release License diff --git a/index.css b/index.css new file mode 100644 index 000000000..7f393742a --- /dev/null +++ b/index.css @@ -0,0 +1,5 @@ +@tailwind base; + +@tailwind components; + +@tailwind utilities; diff --git a/integrations/content-resolution/package.json b/integrations/content-resolution/package.json index 5587595d7..1e17085de 100644 --- a/integrations/content-resolution/package.json +++ b/integrations/content-resolution/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } } diff --git a/integrations/content-resolution/tests/content.test.js b/integrations/content-resolution/tests/content.test.js index a4db09f1b..baf9a3543 100644 --- a/integrations/content-resolution/tests/content.test.js +++ b/integrations/content-resolution/tests/content.test.js @@ -60,7 +60,7 @@ it('looks in the CWD by default', async () => { let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -69,7 +69,7 @@ it('looks in the CWD by default', async () => { result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('looks in the CWD for non-config-relative paths', async () => { @@ -88,7 +88,7 @@ it('looks in the CWD for non-config-relative paths', async () => { let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -97,7 +97,7 @@ it('looks in the CWD for non-config-relative paths', async () => { result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('can look for content files relative to the config', async () => { @@ -113,12 +113,12 @@ it('can look for content files relative to the config', async () => { // Here `./real` doesn't exist next to the config in the root directory let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css``) + expect(result.css).toMatchFormattedCss(css``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -143,7 +143,7 @@ it('it handles ignored globs correctly when not relative to the config', async ( let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -157,7 +157,7 @@ it('it handles ignored globs correctly when not relative to the config', async ( // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('it handles ignored globs correctly when relative to the config', async () => { @@ -177,12 +177,12 @@ it('it handles ignored globs correctly when relative to the config', async () => let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -215,7 +215,7 @@ it('it can resolve symlinks for files when not relative to the config', async () let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -237,7 +237,7 @@ it('it can resolve symlinks for files when not relative to the config', async () // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('it can resolve symlinks for files when relative to the config', async () => { @@ -261,12 +261,12 @@ it('it can resolve symlinks for files when relative to the config', async () => let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); diff --git a/integrations/execute.js b/integrations/execute.js index 6c5f20363..f6dda33a6 100644 --- a/integrations/execute.js +++ b/integrations/execute.js @@ -64,7 +64,7 @@ module.exports = function $(command, options = {}) { messages.splice(0, idx + 1) let actorIdx = actors.indexOf(next) actors.splice(actorIdx, 1) - next.resolve() + next.resolve(message) break } } diff --git a/integrations/io.js b/integrations/io.js index c555ac8ba..0716aac7e 100644 --- a/integrations/io.js +++ b/integrations/io.js @@ -5,6 +5,9 @@ let fs = require('fs/promises') let chokidar = require('chokidar') let resolveToolRoot = require('./resolve-tool-root') +let FILE_STATE = { + NotFound: Symbol(), +} function getWatcherOptions() { return { @@ -28,7 +31,7 @@ module.exports = function ({ cleanup = true, } = {}) { let toolRoot = resolveToolRoot() - let fileCache = {} + let fileCache = new Map() let absoluteOutputFolder = path.resolve(toolRoot, output) let absoluteInputFolder = path.resolve(toolRoot, input) @@ -41,9 +44,9 @@ module.exports = function ({ // Restore all written files afterEach(async () => { await Promise.all( - Object.entries(fileCache).map(async ([file, content]) => { + Array.from(fileCache.entries()).map(async ([file, content]) => { try { - if (content === null) { + if (content === FILE_STATE.NotFound) { return await fs.unlink(file) } else { return await fs.writeFile(file, content, 'utf8') @@ -89,7 +92,7 @@ module.exports = function ({ return { cleanupFile(file) { let filePath = path.resolve(toolRoot, file) - fileCache[filePath] = null + fileCache.set(filePath, FILE_STATE.NotFound) }, async fileExists(file) { let filePath = path.resolve(toolRoot, file) @@ -98,8 +101,11 @@ module.exports = function ({ async removeFile(file) { let filePath = path.resolve(toolRoot, file) - if (!fileCache[filePath]) { - fileCache[filePath] = await fs.readFile(filePath, 'utf8').catch(() => null) + if (!fileCache.has(filePath)) { + fileCache.set( + filePath, + await fs.readFile(filePath, 'utf8').catch(() => FILE_STATE.NotFound) + ) } await fs.unlink(filePath).catch(() => null) @@ -114,20 +120,31 @@ module.exports = function ({ }, async appendToInputFile(file, contents) { let filePath = path.resolve(absoluteInputFolder, file) - if (!fileCache[filePath]) { - fileCache[filePath] = await fs.readFile(filePath, 'utf8') + if (!fileCache.has(filePath)) { + fileCache.set(filePath, await fs.readFile(filePath, 'utf8')) } return fs.appendFile(filePath, contents, 'utf8') }, async writeInputFile(file, contents) { let filePath = path.resolve(absoluteInputFolder, file) - if (!fileCache[filePath]) { + + // Ensure the parent folder of the file exists + if ( + !(await fs + .stat(filePath) + .then(() => true) + .catch(() => false)) + ) { + await fs.mkdir(path.dirname(filePath), { recursive: true }) + } + + if (!fileCache.has(filePath)) { try { - fileCache[filePath] = await fs.readFile(filePath, 'utf8') + fileCache.set(filePath, await fs.readFile(filePath, 'utf8')) } catch (err) { if (err.code === 'ENOENT') { - fileCache[filePath] = null // Sentinel value to `delete` the file afterwards. This also means that we are writing to a `new` file inside the test. + fileCache.set(filePath, FILE_STATE.NotFound) } else { throw err } diff --git a/integrations/parcel/package.json b/integrations/parcel/package.json index c61b3df00..6818c078f 100644 --- a/integrations/parcel/package.json +++ b/integrations/parcel/package.json @@ -19,6 +19,6 @@ } }, "devDependencies": { - "parcel": "^2.8.3" + "parcel": "^2.9.1" } } diff --git a/integrations/parcel/tests/integration.test.js b/integrations/parcel/tests/integration.test.js index b86af727e..36ebe1bf0 100644 --- a/integrations/parcel/tests/integration.test.js +++ b/integrations/parcel/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -40,7 +39,7 @@ describe('static build', () => { 'index.html', html` -

+
` ) await writeInputFile( @@ -58,8 +57,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -74,26 +73,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { @@ -102,7 +88,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await writeInputFile( @@ -122,8 +108,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -138,26 +124,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -199,41 +172,22 @@ describe('watcher', () => { ) await waitForOutputFileChange(/index\.\w+\.css$/, async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -271,41 +225,22 @@ describe('watcher', () => { ) await waitForOutputFileChange(/index\.\w+\.css$/, async () => { - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -328,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -366,7 +301,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } @@ -417,11 +352,11 @@ describe('watcher', () => { expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( css` - /* prettier-ignore */ .btn { - border-radius: .25rem; - padding: .25rem .5rem; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } @@ -438,43 +373,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/postcss-cli/package.json b/integrations/postcss-cli/package.json index 07967231d..337ec0d26 100644 --- a/integrations/postcss-cli/package.json +++ b/integrations/postcss-cli/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } } diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index 46f5a61a6..aefd47214 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile } = require('../../io')({ output: 'dist', @@ -58,41 +57,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -125,41 +105,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -187,23 +148,23 @@ describe('watcher', () => { await writeInputFile( '../tailwind.config.js', javascript` - module.exports = { - content: ['./src/index.html'], - theme: { - extend: { - screens: { - md: '800px' - }, - fontWeight: { - bold: 'bold' - } + module.exports = { + content: ['./src/index.html'], + theme: { + extend: { + screens: { + md: '800px' }, + fontWeight: { + bold: 'bold' + } }, - corePlugins: { - preflight: false, - }, - plugins: [], - } + }, + corePlugins: { + preflight: false, + }, + plugins: [], + } ` ) await runningProcess.onStderr(ready) @@ -277,47 +238,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - /* prettier-ignore */ - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/rollup-sass/package.json b/integrations/rollup-sass/package.json index b1eaa6e94..d61037181 100644 --- a/integrations/rollup-sass/package.json +++ b/integrations/rollup-sass/package.json @@ -18,8 +18,8 @@ } }, "devDependencies": { - "rollup": "^3.21.0", + "rollup": "^3.25.1", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "^1.63.4" } } diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index 19a769565..90a3831ff 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile } = require('../../io')({ output: 'dist', @@ -58,41 +57,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -125,41 +105,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -275,43 +236,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) @@ -370,43 +313,25 @@ describe('watcher', () => { css` @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/rollup/package.json b/integrations/rollup/package.json index 21da41dbd..4fb815e97 100644 --- a/integrations/rollup/package.json +++ b/integrations/rollup/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "rollup": "^3.21.0", + "rollup": "^3.25.1", "rollup-plugin-postcss": "^4.0.2" } } diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index c3209af65..6a35285e3 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -30,7 +29,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -46,8 +45,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -62,31 +61,18 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -104,8 +90,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -120,26 +106,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -172,41 +145,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -389,46 +324,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/tailwindcss-cli/fixtures/example-app/src/index.css b/integrations/tailwindcss-cli/fixtures/example-app/src/index.css new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/integrations/tailwindcss-cli/fixtures/example-app/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/integrations/tailwindcss-cli/fixtures/example-app/src/index.html b/integrations/tailwindcss-cli/fixtures/example-app/src/index.html new file mode 100644 index 000000000..b956240c2 --- /dev/null +++ b/integrations/tailwindcss-cli/fixtures/example-app/src/index.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index 0c42ce0cc..7647c6639 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -2,7 +2,6 @@ let path = require('path') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') let resolveToolRoot = require('../../resolve-tool-root') -let { env } = require('../../../lib/lib/sharedState') let version = require('../../../package.json').version @@ -19,7 +18,6 @@ let { }) let EXECUTABLE = 'node ../../lib/cli.js' -let testStable = env.ENGINE === 'stable' ? test : test.skip function dedent(input) { let lines = input.split('\n') @@ -98,26 +96,35 @@ describe('Build command', () => { expect(withoutMinify.length).toBeGreaterThan(withMinify.length) }) - testStable('--no-autoprefixer', async () => { + // Deprecated + test('--no-autoprefixer (should produce a warning)', async () => { await writeInputFile('index.html', html`
`) + await writeInputFile( + 'index.css', + css` + @tailwind utilities; + ` + ) - await $(`${EXECUTABLE} --output ./dist/main.css`) - let withAutoprefixer = await readOutputFile('main.css') + let runningProcess = $( + `${EXECUTABLE} --input ./src/index.css --output ./dist/main.css --no-autoprefixer` + ) + let warning = runningProcess.onStderr((message) => message.includes('--no-autoprefixer')) + await runningProcess + expect(await warning).toMatchInlineSnapshot(` + "[deprecation] The --no-autoprefixer flag is deprecated and has no effect. + " + `) + let withoutAutoprefixer = await readOutputFile('main.css') - expect(withAutoprefixer).toIncludeCss(css` - .select-none { + // This contains --webkit-user-select which may be strange, but it is expected because we are + // not handling the `--no-autoprefixer` flag anymore at all. + expect(withoutAutoprefixer).toMatchInlineSnapshot(` + ".select-none { -webkit-user-select: none; user-select: none; } - `) - - await $(`${EXECUTABLE} --output ./dist/main.css --no-autoprefixer`) - let withoutAutoprefixer = await readOutputFile('main.css') - - expect(withoutAutoprefixer).toIncludeCss(css` - .select-none { - user-select: none; - } + " `) }) @@ -143,7 +150,7 @@ describe('Build command', () => { theme: { extend: { fontWeight: { - bold: 'BOLD', + bold: 'bold', }, }, }, @@ -164,7 +171,7 @@ describe('Build command', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` .font-bold { - font-weight: BOLD; + font-weight: bold; } ` ) @@ -184,7 +191,7 @@ describe('Build command', () => { ) }) - testStable('--postcss (postcss.config.js)', async () => { + test('--postcss (postcss.config.js)', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -196,7 +203,7 @@ describe('Build command', () => { function before(root, result) { // Inject a custom component with @apply rules to prove that we run // this _before_ the actual tailwind plugin. - let btn = postcss.parse('.btn { @apply bg-red-500 px-2 py-1 }') + let btn = postcss.parse('.btn { @apply flex px-2 py-1 }') root.append(btn.nodes) }, function tailwindcss() { @@ -217,45 +224,21 @@ describe('Build command', () => { await $(`${EXECUTABLE} --output ./dist/main.css --postcss`) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold-after { + font-weight: 700; + } - .btn-after { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } - - .btn-after { - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } + .btn-after { + padding: 0.25rem 0.5rem; + display: flex; + } + ` + ) }) - testStable('--postcss (custom.postcss.config.js)', async () => { + test('--postcss (custom.postcss.config.js)', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -267,7 +250,7 @@ describe('Build command', () => { function before(root, result) { // Inject a custom component with @apply rules to prove that we run // this _before_ the actual tailwind plugin. - let btn = postcss.parse('.btn { @apply bg-red-500 px-2 py-1 }') + let btn = postcss.parse('.btn { @apply flex px-2 py-1 }') root.append(btn.nodes) }, function tailwindcss() { @@ -288,45 +271,21 @@ describe('Build command', () => { await $(`${EXECUTABLE} --output ./dist/main.css --postcss ./custom.postcss.config.js`) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold-after { + font-weight: 700; + } - .btn-after { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } - - .btn-after { - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } + .btn-after { + padding: 0.25rem 0.5rem; + display: flex; + } + ` + ) }) - testStable('--postcss supports process options', async () => { + test('--postcss supports process options', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -360,7 +319,7 @@ describe('Build command', () => { expect(contents).toContain(`/*# sourceMappingURL`) }) - testStable('--postcss supports process options with custom config', async () => { + test('--postcss supports process options with custom config', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -472,7 +431,7 @@ describe('Build command', () => { css` @media (min-width: 768px) { .md\:something-cool { - color: blue; + color: #00f; } } ` @@ -481,10 +440,18 @@ describe('Build command', () => { return runningProcess.stop() }) - testStable('postcss-import is included when using a custom postcss configuration', async () => { + test('postcss-import is included when using a custom postcss configuration', async () => { cleanupFile('src/test.css') await writeInputFile('index.html', html`
`) + await writeInputFile( + 'imported.css', + css` + .foo { + color: white; + } + ` + ) await writeInputFile( 'test.css', css` @@ -501,7 +468,9 @@ describe('Build command', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` - @import './imported.css'; + .foo { + color: #fff; + } ` ) }) @@ -509,28 +478,8 @@ describe('Build command', () => { test('--help', async () => { let { combined } = await $(`${EXECUTABLE} --help`) - if (env.ENGINE === 'oxide') { - expect(dedent(combined)).toEqual( - dedent(` - tailwindcss v${version} - - Usage: - tailwindcss build [options] - - Options: - -i, --input Input file - -o, --output Output file - -w, --watch Watch for changes and rebuild as needed - -p, --poll Use polling instead of filesystem events when watching - --content Content paths to use for removing unused classes - -m, --minify Minify the output - -c, --config Path to a custom config file - -h, --help Display usage information - `) - ) - } else if (env.ENGINE === 'stable') { - expect(dedent(combined)).toEqual( - dedent(` + expect(dedent(combined)).toEqual( + dedent(` tailwindcss v${version} Usage: @@ -545,11 +494,9 @@ describe('Build command', () => { --postcss Load custom PostCSS configuration -m, --minify Minify the output -c, --config Path to a custom config file - --no-autoprefixer Disable autoprefixer -h, --help Display usage information `) - ) - } + ) }) }) @@ -562,7 +509,6 @@ describe('Init command', () => { { flags: ['--ts', '--full'], name: 'tailwind.config.ts' }, { flags: ['--esm', '--full'], name: 'tailwind.config.js' }, ])('works with all these flags: %j', async ({ flags, name }) => { - cleanupFile(name) await removeFile(name) let { combined } = await $(`${EXECUTABLE} init ${flags.join(' ')}`) @@ -611,7 +557,7 @@ describe('Init command', () => { expect((await readOutputFile('../full.config.js')).split('\n').length).toBeGreaterThan(50) }) - testStable('--postcss', async () => { + test('--postcss', async () => { expect(await fileExists('postcss.config.js')).toBe(true) await removeFile('postcss.config.js') expect(await fileExists('postcss.config.js')).toBe(false) @@ -631,24 +577,8 @@ describe('Init command', () => { test('--help', async () => { let { combined } = await $(`${EXECUTABLE} init --help`) - if (env.ENGINE === 'oxide') { - expect(dedent(combined)).toEqual( - dedent(` - tailwindcss v${version} - - Usage: - tailwindcss init [options] - - Options: - --esm Initialize configuration file as ESM - --ts Initialize configuration file as TypeScript - -f, --full Include the default values for all options in the generated configuration file - -h, --help Display usage information - `) - ) - } else if (env.ENGINE === 'stable') { - expect(dedent(combined)).toEqual( - dedent(` + expect(dedent(combined)).toEqual( + dedent(` tailwindcss v${version} Usage: @@ -661,12 +591,10 @@ describe('Init command', () => { -f, --full Include the default values for all options in the generated configuration file -h, --help Display usage information `) - ) - } + ) }) test('ESM config is created by default in an ESM project', async () => { - cleanupFile('tailwind.config.js') await removeFile('tailwind.config.js') let pkg = await readOutputFile('../package.json') @@ -696,7 +624,6 @@ describe('Init command', () => { }) test('CJS config is created by default in a non-ESM project', async () => { - cleanupFile('tailwind.config.js') await removeFile('tailwind.config.js') let pkg = await readOutputFile('../package.json') diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index 75c9779af..ce02e7fdd 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -1,7 +1,7 @@ let fs = require('fs') +let path = require('path') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -55,7 +55,7 @@ describe('static build', () => { content: { files: ['./src/index.html'], }, - safelist: ['bg-red-500','bg-red-600'], + safelist: ['flex','block'], theme: { extend: { }, @@ -72,48 +72,26 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .block { + display: block; + } - .bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } + .flex { + display: flex; + } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - - .bg-red-600 { - background-color: #dc2626; - } - - .font-bold { - font-weight: 700; - } - ` - ) - } + .font-bold { + font-weight: 700; + } + ` + ) }) it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -129,8 +107,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0 }, }, }, @@ -145,31 +123,18 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -187,8 +152,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0 }, }, }, @@ -203,30 +168,17 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can read from a config file from an @config directive', async () => { - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -246,8 +198,8 @@ describe('static build', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -262,32 +214,19 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can read from a config file from an @config directive inside an @import from postcss-import', async () => { await fs.promises.mkdir('./src/config', { recursive: true }) - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'config/myconfig.css', css` @@ -313,8 +252,8 @@ describe('static build', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -329,26 +268,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('should work with raw content', async () => { @@ -357,7 +283,7 @@ describe('static build', () => { javascript` module.exports = { content: { - files: [{ raw: 'bg-red-500'}], + files: [{ raw: 'flex'}], }, theme: { extend: { @@ -375,26 +301,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + ` + ) }) }) @@ -427,41 +340,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -494,41 +388,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -696,55 +571,31 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded flex px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + display: flex; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) test('listens for changes to the @config directive', async () => { - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -764,8 +615,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -785,8 +636,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#ff7', + zIndex: { + primary: 10 } }, }, @@ -800,26 +651,13 @@ describe('watcher', () => { let runningProcess = $('node ../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w') await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) await writeInputFile( 'index.css', @@ -832,26 +670,13 @@ describe('watcher', () => { ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 119 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff7; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 10; + } + ` + ) await writeInputFile( 'tailwind.2.config.js', @@ -863,8 +688,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#fff', + zIndex: { + primary: 20 } }, }, @@ -876,26 +701,13 @@ describe('watcher', () => { ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #fff; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 20; + } + ` + ) return runningProcess.stop() }) @@ -1000,4 +812,560 @@ describe('watcher', () => { return runningProcess.stop() }) + + describe('auto content', () => { + let { readOutputFile, writeInputFile } = require('../../io')({ + output: 'fixtures/example-app/dist', + input: 'fixtures/example-app/src', + }) + let options = { + cwd: path.resolve(__dirname, '..', 'fixtures', 'example-app'), + } + + it('should detect classes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + text-decoration-line: underline; + } + ` + ) + + // Make a change + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in new files in existing folders with a known extension', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + text-decoration-line: underline; + } + ` + ) + + // Make a change to a new file in an existing folder with a known extension. + + await writeInputFile('other.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan ignored files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('../.gitignore', 'generated-folder/') + await writeInputFile('../generated-folder/bad.html', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for known binary files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example-1.png', html`
`) + await writeInputFile('example-2.mp4', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored extensions (such as css/scss/less/...)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example.css', html`
`) + await writeInputFile('example.less', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored files (such as package-lock.json)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('package-lock.json', html`
`) + await writeInputFile('yarn.lock', html`
`) + await writeInputFile('pnpm-lock.yaml', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not include the tailwind.config.js file as a template file', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + // Example class that should not be included: flex italic + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .flex { + display: flex; + } + ` + ) + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should optimize the globs and ensure that nested ignored folders are not scanned', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/a.html', html`
`) + await writeInputFile('index.html', html`
`) + await writeInputFile('nested/index.html', html`
`) + await writeInputFile('nested/node_modules/index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // Root node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-30 { + z-index: 30; + } + ` + ) + + // Nested node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-40 { + z-index: 40; + } + ` + ) + + return runningProcess.stop() + }) + + it("should use auto content when content is explicitly set to 'auto'", async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: 'auto', + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/a.html', html`
`) + await writeInputFile('index.html', html`
`) + await writeInputFile('nested/index.html', html`
`) + await writeInputFile('nested/node_modules/index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // Root node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-30 { + z-index: 30; + } + ` + ) + + // Nested node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-40 { + z-index: 40; + } + ` + ) + + return runningProcess.stop() + }) + + it('should be possible to merge "auto" and custom defined paths', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: ['auto'], // Ignoring the library-example.html file for now + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/library-example.html', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // example.html should be ignored right now + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: ['auto', 'node_modules/library-example.html'], // Explicitly adding the library-example.html file + corePlugins: { + preflight: false, + }, + } + ` + ) + await runningProcess.onStderr(ready) + + // z-10 from `example.html` should be available now + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + return runningProcess.stop() + }) + }) }) diff --git a/integrations/vite/package.json b/integrations/vite/package.json index 4b9649cab..3c412435d 100644 --- a/integrations/vite/package.json +++ b/integrations/vite/package.json @@ -21,6 +21,6 @@ }, "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.9" } } diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index b1a8163b2..b0a4f6c79 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -2,7 +2,6 @@ require('isomorphic-fetch') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -48,7 +47,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await removeFile('tailwind.config.js') @@ -59,8 +58,8 @@ describe('static build', () => { content: ['index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -75,26 +74,13 @@ describe('static build', () => { env: { NODE_ENV: 'production', NO_COLOR: '1' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { @@ -102,7 +88,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await removeFile('tailwind.config.js') @@ -115,8 +101,8 @@ describe('static build', () => { content: ['index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -131,26 +117,13 @@ describe('static build', () => { env: { NODE_ENV: 'production', NO_COLOR: '1' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -191,41 +164,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStdout((message) => message.includes('page reload')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -262,41 +216,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStdout((message) => message.includes('page reload')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -428,49 +363,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStdout((message) => message.includes('hmr update /index.css')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index e2e24cf45..ae7011edd 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -28,7 +27,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -44,8 +43,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -58,31 +57,18 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -100,8 +86,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -114,26 +100,13 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -169,41 +142,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -394,46 +329,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index 83b42f5f8..c1f0a0629 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -28,7 +27,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -44,8 +43,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -58,31 +57,18 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -100,8 +86,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -114,26 +100,13 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -169,41 +142,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -394,46 +329,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) @@ -447,7 +361,7 @@ describe('watcher', () => { content: { files: ['./src/index.html'], }, - safelist: ['bg-red-500','bg-red-600'], + safelist: ['z-0', 'z-10'], theme: { extend: { }, @@ -464,43 +378,21 @@ describe('watcher', () => { await waitForOutputFileCreation('main.css') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } - .bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } + .z-10 { + z-index: 10; + } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - - .bg-red-600 { - background-color: #dc2626; - } - - .font-bold { - font-weight: 700; - } - ` - ) - } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/jest/customMatchers.js b/jest/customMatchers.js index 9b1c6b6d0..8e262bdd0 100644 --- a/jest/customMatchers.js +++ b/jest/customMatchers.js @@ -1,6 +1,5 @@ const prettier = require('prettier') const { diff } = require('jest-diff') -const lightningcss = require('lightningcss') const log = require('../src/util/log').default let warn @@ -22,46 +21,7 @@ function formatPrettier(input) { } function format(input) { - try { - return lightningcss - .transform({ - filename: 'input.css', - code: Buffer.from(input), - minify: false, - targets: { chrome: 106 << 16 }, - drafts: { - nesting: true, - customMedia: true, - }, - }) - .code.toString('utf8') - } catch (err) { - try { - // Lightning CSS is pretty strict, so it will fail for `@media screen(md) {}` for example, - // in that case we can fallback to prettier since it doesn't really care. However if an - // actual syntax error is made, then we still want to show the proper error. - return formatPrettier(input.replace(/\n/g, '')) - } catch { - let lines = err.source.split('\n') - let e = new Error( - [ - 'Error formatting using Lightning CSS:', - '', - ...[ - '```css', - ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), - ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), - ...lines.slice(err.loc.line, err.loc.line + 2), - '```', - ], - ].join('\n') - ) - if (Error.captureStackTrace) { - Error.captureStackTrace(e, toMatchFormattedCss) - } - throw e - } - } + return formatPrettier(input).replace(/\n{2,}/g, '\n') } function toMatchFormattedCss(received = '', argument = '') { @@ -86,10 +46,7 @@ function toMatchFormattedCss(received = '', argument = '') { ) } : () => { - let actual = formatPrettier(formattedReceived).replace(/\n\n/g, '\n') - let expected = formatPrettier(formattedArgument).replace(/\n\n/g, '\n') - - let diffString = diff(expected, actual, { + let diffString = diff(formattedArgument, formattedReceived, { expand: this.expand, }) @@ -98,8 +55,8 @@ function toMatchFormattedCss(received = '', argument = '') { '\n\n' + (diffString && diffString.includes('- Expect') ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) + : `Expected: ${this.utils.printExpected(formattedArgument)}\n` + + `Received: ${this.utils.printReceived(formattedReceived)}`) ) } @@ -107,13 +64,10 @@ function toMatchFormattedCss(received = '', argument = '') { } expect.extend({ - // Compare two CSS strings with all whitespace removed - // This is probably naive but it's fast and works well enough. - toMatchCss: toMatchFormattedCss, toMatchFormattedCss: toMatchFormattedCss, toIncludeCss(received, argument) { let options = { - comment: 'stripped(received).includes(stripped(argument))', + comment: 'formatCSS(received).includes(formatCSS(argument))', isNot: this.isNot, promise: this.promise, } diff --git a/oxide/Cargo.lock b/oxide/Cargo.lock index 5b959d726..06f4e1b6e 100644 --- a/oxide/Cargo.lock +++ b/oxide/Cargo.lock @@ -11,13 +11,71 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -35,22 +93,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bstr" -version = "0.2.17" +name = "bitflags" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] +checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" [[package]] name = "bstr" -version = "1.0.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" dependencies = [ "memchr", "once_cell", @@ -60,9 +112,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -76,6 +128,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -88,47 +146,58 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "textwrap", "unicode-width", ] [[package]] name = "clap" -version = "4.0.26" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "convert_case" @@ -191,9 +260,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -201,9 +270,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -212,9 +281,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", @@ -235,22 +304,21 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] [[package]] name = "csv" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" dependencies = [ - "bstr 0.2.17", "csv-core", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] @@ -266,19 +334,49 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.26" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +checksum = "990a40740adf249724a6000c0fc4bd574712f50bb17c2d6f6cec837ae2f0ee75" dependencies = [ "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] name = "fnv" @@ -297,12 +395,12 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", - "bstr 0.2.17", + "aho-corasick 0.7.20", + "bstr", "fnv", "log", "regex", @@ -314,7 +412,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -327,9 +425,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -341,12 +439,26 @@ dependencies = [ ] [[package]] -name = "ignore" -version = "0.4.18" +name = "hermit-abi" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -358,6 +470,38 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -369,21 +513,15 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -396,9 +534,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -411,13 +549,16 @@ dependencies = [ ] [[package]] -name = "log" -version = "0.4.17" +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "matchers" @@ -436,24 +577,24 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "napi" -version = "2.10.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "466b16c759694cb07fbb023b0bde55afcc2ae35e8c0264b070c86a3e9a18cb6c" +checksum = "d7f0a2e93526dd9c8c522d72a4d0c88678be8966fabe9fb8f2947fde6339b682" dependencies = [ - "bitflags", + "bitflags 2.3.1", "ctor", + "napi-derive", "napi-sys", "once_cell", - "thread_local", ] [[package]] @@ -464,36 +605,38 @@ checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e" [[package]] name = "napi-derive" -version = "2.11.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e367c72b3f0243d490f0cf4feed9a28e40e4e9cba16912951dbeccf6c607576" +checksum = "da1c6a8fa84d549aa8708fcd062372bf8ec6e849de39016ab921067d21bde367" dependencies = [ + "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "napi-derive-backend" -version = "1.0.45" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2cf4ba5f1f6d51b9b5e2d809e229201f3aa14f198d58ec9ba4ecf82dbabb381" +checksum = "20bbc7c69168d06a848f925ec5f0e0997f98e8c8d4f2cc30157f0da51c009e17" dependencies = [ "convert_case", "once_cell", "proc-macro2", "quote", "regex", - "syn", + "semver", + "syn 1.0.109", ] [[package]] name = "napi-sys" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529671ebfae679f2ce9630b62dd53c72c56b3eb8b2c852e7e2fa91704ff93d67" +checksum = "166b5ef52a3ab5575047a9fe8d4a030cdd0f63c96f071cd6907674453b07bae3" dependencies = [ "libloading", ] @@ -519,19 +662,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "oorandom" @@ -539,12 +682,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "overload" version = "0.1.1" @@ -585,64 +722,39 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -651,14 +763,23 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.7.0" +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "aho-corasick", + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +dependencies = [ + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.2", ] [[package]] @@ -667,20 +788,40 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -698,10 +839,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "serde" -version = "1.0.147" +name = "semver" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" [[package]] name = "serde_cbor" @@ -715,22 +862,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ - "itoa 1.0.4", + "itoa", "ryu", "serde", ] @@ -758,9 +905,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -786,33 +944,40 @@ version = "0.1.0" name = "tailwindcss-core" version = "0.1.0" dependencies = [ - "bstr 1.0.1", + "bstr", "criterion", "crossbeam", "fxhash", "globwalk", + "ignore", "log", "rayon", + "tempfile", "tracing", "tracing-subscriber", + "walkdir", ] [[package]] name = "tailwindcss-oxide" version = "0.1.0" dependencies = [ - "clap 4.0.26", + "clap 4.3.0", "rayon", "tailwindcss-core", ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "tempfile" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ - "winapi-util", + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.45.0", ] [[package]] @@ -826,10 +991,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -857,20 +1023,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -889,9 +1055,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -907,9 +1073,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-segmentation" @@ -923,34 +1089,33 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -958,24 +1123,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -983,28 +1148,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -1040,3 +1205,135 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/oxide/crates/cli/src/main.rs b/oxide/crates/cli/src/main.rs index cda7c48aa..767d440ae 100644 --- a/oxide/crates/cli/src/main.rs +++ b/oxide/crates/cli/src/main.rs @@ -105,7 +105,7 @@ fn main() -> Result<(), std::io::Error> { let candidates = content_paths.par_bridge().flat_map(|path| { read_lines(path) .unwrap() - .filter_map(Result::ok) + .map_while(Result::ok) .par_bridge() .flat_map_iter(|line| { Extractor::unique(line.as_bytes(), Default::default()) diff --git a/oxide/crates/core/Cargo.toml b/oxide/crates/core/Cargo.toml index ae895f34a..3b0b3d123 100644 --- a/oxide/crates/core/Cargo.toml +++ b/oxide/crates/core/Cargo.toml @@ -12,14 +12,17 @@ fxhash = "0.2.1" crossbeam = "0.8.2" tracing = { version = "0.1.37", features = [] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +walkdir = "2.3.3" +ignore = "0.4.20" [dev-dependencies] criterion = { version = "0.3", features = ['html_reports'] } +tempfile = "3.5.0" [[bench]] name = "parse_candidates" harness = false [[bench]] -name = "parse_candidate_strings_from_files" +name = "parse_candidate_strings" harness = false diff --git a/oxide/crates/core/benches/parse_candidate_strings_from_files.rs b/oxide/crates/core/benches/parse_candidate_strings.rs similarity index 85% rename from oxide/crates/core/benches/parse_candidate_strings_from_files.rs rename to oxide/crates/core/benches/parse_candidate_strings.rs index a9e5faf9d..16672f058 100644 --- a/oxide/crates/core/benches/parse_candidate_strings_from_files.rs +++ b/oxide/crates/core/benches/parse_candidate_strings.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, Criterion}; use std::path::PathBuf; -use tailwindcss_core::{parse_candidate_strings_from_files, ChangedContent}; +use tailwindcss_core::{parse_candidate_strings, ChangedContent, Parsing, IO}; pub fn criterion_benchmark(c: &mut Criterion) { // current_dir will be set to ./crates/core @@ -11,7 +11,6 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut all_files: Vec<(u64, PathBuf)> = std::fs::read_dir(fixtures_path) .unwrap() - .into_iter() .filter_map(Result::ok) .map(|dir_entry| dir_entry.path()) .filter(|path| path.is_file()) @@ -51,8 +50,13 @@ pub fn criterion_benchmark(c: &mut Criterion) { }) .collect(); - c.bench_function("parse_candidate_strings_from_files", |b| { - b.iter(|| parse_candidate_strings_from_files(changed_content.clone())) + c.bench_function("parse_candidate_strings", |b| { + b.iter(|| { + parse_candidate_strings( + changed_content.clone(), + Parsing::Parallel as u8 | IO::Parallel as u8, + ) + }) }); } diff --git a/oxide/crates/core/benches/parse_candidates.rs b/oxide/crates/core/benches/parse_candidates.rs index 55c919471..aacc1469e 100644 --- a/oxide/crates/core/benches/parse_candidates.rs +++ b/oxide/crates/core/benches/parse_candidates.rs @@ -31,6 +31,18 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("parse_candidate_strings (real world)", |b| { b.iter(|| parse(include_bytes!("./fixtures/template-499.html"))) }); + + let mut group = c.benchmark_group("sample-size-example"); + group.sample_size(10); + + group.bench_function("parse_candidate_strings (fast space skipping)", |b| { + let count = 10_000; + let crazy1 = format!("{}underline", " ".repeat(count)); + let crazy2 = crazy1.repeat(count); + let crazy3 = crazy2.as_bytes(); + + b.iter(|| parse(black_box(crazy3))) + }); } criterion_group!(benches, criterion_benchmark); diff --git a/oxide/crates/core/src/candidate.rs b/oxide/crates/core/src/candidate.rs index b77ace8b2..3a608a152 100644 --- a/oxide/crates/core/src/candidate.rs +++ b/oxide/crates/core/src/candidate.rs @@ -22,7 +22,6 @@ impl Candidate { x == ':' && !in_arbitrary } }) - .into_iter() .collect::>(); let utility = match parts.pop() { diff --git a/oxide/crates/core/src/cursor.rs b/oxide/crates/core/src/cursor.rs new file mode 100644 index 000000000..0c422c6ff --- /dev/null +++ b/oxide/crates/core/src/cursor.rs @@ -0,0 +1,159 @@ +use std::{ascii::escape_default, fmt::Display}; + +#[derive(Debug, Clone)] +pub struct Cursor<'a> { + // The input we're scanning + pub input: &'a [u8], + + // The location of the cursor in the input + pub pos: usize, + + /// Is the cursor at the start of the input + pub at_start: bool, + + /// Is the cursor at the end of the input + pub at_end: bool, + + /// The previously consumed character + /// If `at_start` is true, this will be NUL + pub prev: u8, + + /// The current character + pub curr: u8, + + /// The upcoming character (if any) + /// If `at_end` is true, this will be NUL + pub next: u8, +} + +impl<'a> Cursor<'a> { + pub fn new(input: &'a [u8]) -> Self { + let mut cursor = Self { + input, + pos: 0, + at_start: true, + at_end: false, + prev: 0x00, + curr: 0x00, + next: 0x00, + }; + cursor.move_to(0); + cursor + } + + pub fn rewind_by(&mut self, amount: usize) { + self.move_to(self.pos.saturating_sub(amount)); + } + + pub fn advance_by(&mut self, amount: usize) { + self.move_to(self.pos.saturating_add(amount)); + } + + pub fn move_to(&mut self, pos: usize) { + let len = self.input.len(); + let pos = pos.clamp(0, len); + + self.pos = pos; + self.at_start = pos == 0; + self.at_end = pos + 1 >= len; + + self.prev = if pos > 0 { self.input[pos - 1] } else { 0x00 }; + self.curr = if pos < len { self.input[pos] } else { 0x00 }; + self.next = if pos + 1 < len { + self.input[pos + 1] + } else { + 0x00 + }; + } +} + +impl<'a> Display for Cursor<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let len = self.input.len().to_string(); + + let pos = format!("{: >len_count$}", self.pos, len_count = len.len()); + write!(f, "{}/{} ", pos, len)?; + + if self.at_start { + write!(f, "S ")?; + } else if self.at_end { + write!(f, "E ")?; + } else { + write!(f, "M ")?; + } + + fn to_str(c: u8) -> String { + if c == 0x00 { + "NUL".into() + } else { + format!("{:?}", escape_default(c).to_string()) + } + } + + write!( + f, + "[{} {} {}]", + to_str(self.prev), + to_str(self.curr), + to_str(self.next) + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_cursor() { + let mut cursor = Cursor::new(b"hello world"); + assert_eq!(cursor.pos, 0); + assert!(cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, 0x00); + assert_eq!(cursor.curr, b'h'); + assert_eq!(cursor.next, b'e'); + + cursor.advance_by(1); + assert_eq!(cursor.pos, 1); + assert!(!cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, b'h'); + assert_eq!(cursor.curr, b'e'); + assert_eq!(cursor.next, b'l'); + + // Advancing too far should stop at the end + cursor.advance_by(10); + assert_eq!(cursor.pos, 11); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'd'); + assert_eq!(cursor.curr, 0x00); + assert_eq!(cursor.next, 0x00); + + // Can't advance past the end + cursor.advance_by(1); + assert_eq!(cursor.pos, 11); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'd'); + assert_eq!(cursor.curr, 0x00); + assert_eq!(cursor.next, 0x00); + + cursor.rewind_by(1); + assert_eq!(cursor.pos, 10); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'l'); + assert_eq!(cursor.curr, b'd'); + assert_eq!(cursor.next, 0x00); + + cursor.rewind_by(10); + assert_eq!(cursor.pos, 0); + assert!(cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, 0x00); + assert_eq!(cursor.curr, b'h'); + assert_eq!(cursor.next, b'e'); + } +} diff --git a/oxide/crates/core/src/fast_skip.rs b/oxide/crates/core/src/fast_skip.rs new file mode 100644 index 000000000..488e61bd6 --- /dev/null +++ b/oxide/crates/core/src/fast_skip.rs @@ -0,0 +1,89 @@ +use crate::cursor::Cursor; + +const STRIDE: usize = 16; +type Mask = [bool; STRIDE]; + +#[inline(always)] +pub fn fast_skip(cursor: &Cursor) -> Option { + // If we don't have enough bytes left to check then bail early + if cursor.pos + STRIDE >= cursor.input.len() { + return None; + } + + if !cursor.curr.is_ascii_whitespace() { + return None; + } + + let mut offset = 1; + + // SAFETY: We've already checked (indirectly) that this index is valid + let remaining = unsafe { cursor.input.get_unchecked(cursor.pos..) }; + + // NOTE: This loop uses primitives designed to be auto-vectorized + // Do not change this loop without benchmarking the results + // And checking the generated assembly using godbolt.org + for (i, chunk) in remaining.chunks_exact(STRIDE).enumerate() { + let value = load(chunk); + let is_whitespace = is_ascii_whitespace(value); + let is_all_whitespace = all_true(is_whitespace); + + if is_all_whitespace { + offset = (i + 1) * STRIDE; + } else { + break; + } + } + + Some(cursor.pos + offset) +} + +#[inline(always)] +fn load(input: &[u8]) -> [u8; STRIDE] { + let mut value = [0u8; STRIDE]; + value.copy_from_slice(input); + value +} + +#[inline(always)] +fn eq(input: [u8; STRIDE], val: u8) -> Mask { + let mut res = [false; STRIDE]; + for n in 0..STRIDE { + res[n] = input[n] == val + } + res +} + +#[inline(always)] +fn or(a: [bool; STRIDE], b: [bool; STRIDE]) -> [bool; STRIDE] { + let mut res = [false; STRIDE]; + for n in 0..STRIDE { + res[n] = a[n] | b[n]; + } + res +} + +#[inline(always)] +fn all_true(a: [bool; STRIDE]) -> bool { + let mut res = true; + for item in a.iter().take(STRIDE) { + res &= item; + } + res +} + +#[inline(always)] +fn is_ascii_whitespace(value: [u8; STRIDE]) -> [bool; STRIDE] { + let whitespace_1 = eq(value, b'\t'); + let whitespace_2 = eq(value, b'\n'); + let whitespace_3 = eq(value, b'\x0C'); + let whitespace_4 = eq(value, b'\r'); + let whitespace_5 = eq(value, b' '); + + or( + or( + or(or(whitespace_1, whitespace_2), whitespace_3), + whitespace_4, + ), + whitespace_5, + ) +} diff --git a/oxide/crates/core/src/fixtures/binary-extensions.txt b/oxide/crates/core/src/fixtures/binary-extensions.txt new file mode 100644 index 000000000..b7cee312c --- /dev/null +++ b/oxide/crates/core/src/fixtures/binary-extensions.txt @@ -0,0 +1,259 @@ +3dm +3ds +3g2 +3gp +7z +DS_Store +a +aac +adp +ai +aif +aiff +alz +ape +apk +appimage +ar +arj +asf +au +avi +bak +baml +bh +bin +bk +bmp +btif +bz2 +bzip2 +cab +caf +cgm +class +cmx +cpio +cr2 +cur +dat +dcm +deb +dex +djvu +dll +dmg +dng +doc +docm +docx +dot +dotm +dra +dsk +dts +dtshd +dvb +dwg +dxf +ecelp4800 +ecelp7470 +ecelp9600 +egg +eol +eot +epub +exe +f4v +fbs +fh +fla +flac +flatpak +fli +flv +fpx +fst +fvt +g3 +gh +gif +graffle +gz +gzip +h261 +h263 +h264 +icns +ico +ief +img +ipa +iso +jar +jpeg +jpg +jpgv +jpm +jxr +key +ktx +lha +lib +lockb +lvp +lz +lzh +lzma +lzo +m3u +m4a +m4v +mar +mdi +mht +mid +midi +mj2 +mka +mkv +mmr +mng +mobi +mov +movie +mp3 +mp4 +mp4a +mpeg +mpg +mpga +mxu +nef +npx +numbers +nupkg +o +odp +ods +odt +oga +ogg +ogv +otf +ott +pages +pbm +pcx +pdb +pdf +pea +pgm +pic +png +pnm +pot +potm +potx +ppa +ppam +ppm +pps +ppsm +ppsx +ppt +pptm +pptx +psd +pya +pyc +pyo +pyv +qt +rar +ras +raw +resources +rgb +rip +rlc +rmf +rmvb +rpm +rtf +rz +s3m +s7z +scpt +sgi +shar +sil +sketch +slk +smv +snap +snk +so +stl +sub +suo +swf +tar +tbz +tbz2 +tga +tgz +thmx +tif +tiff +tlz +ttc +ttf +txz +udf +uvh +uvi +uvm +uvp +uvs +uvu +viv +vob +war +wav +wax +wbmp +wdp +weba +webm +webp +whl +wim +wm +wma +wmv +wmx +woff +woff2 +wrm +wvx +xbm +xif +xla +xlam +xls +xlsb +xlsm +xlsx +xlt +xltm +xltx +xm +xmind +xpi +xpm +xwd +xz +z +zip +zipx diff --git a/oxide/crates/core/src/fixtures/ignored-extensions.txt b/oxide/crates/core/src/fixtures/ignored-extensions.txt new file mode 100644 index 000000000..f147c24fe --- /dev/null +++ b/oxide/crates/core/src/fixtures/ignored-extensions.txt @@ -0,0 +1,6 @@ +css +less +lock +sass +scss +styl diff --git a/oxide/crates/core/src/fixtures/ignored-files.txt b/oxide/crates/core/src/fixtures/ignored-files.txt new file mode 100644 index 000000000..45d4ced87 --- /dev/null +++ b/oxide/crates/core/src/fixtures/ignored-files.txt @@ -0,0 +1,3 @@ +package-lock.json +pnpm-lock.yaml +bun.lockb diff --git a/oxide/crates/core/src/fixtures/template-extensions.txt b/oxide/crates/core/src/fixtures/template-extensions.txt new file mode 100644 index 000000000..c059eff3a --- /dev/null +++ b/oxide/crates/core/src/fixtures/template-extensions.txt @@ -0,0 +1,57 @@ +# HTML +html +pug + +# JS +astro +cjs +cts +jade +js +jsx +mjs +mts +svelte +ts +tsx +vue + +# Markdown +md +mdx + +# ASP +aspx +razor + +# Handlebars +handlebars +hbs +mustache + +# PHP +php +twig + +# Ruby +erb +haml +liquid +rb +rhtml +slim + +# Elixir / Phoenix +eex +heex + +# Nunjucks +njk +nunjucks + +# Python +py +tpl + +# Rust +rs diff --git a/oxide/crates/core/src/glob.rs b/oxide/crates/core/src/glob.rs index f9e355075..f0ed8ab71 100644 --- a/oxide/crates/core/src/glob.rs +++ b/oxide/crates/core/src/glob.rs @@ -12,7 +12,6 @@ pub fn fast_glob( .follow_links(true) .build() .unwrap() - .into_iter() .filter_map(Result::ok) .map(|file| file.path().to_path_buf()) })) diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 84713e61b..9596c6855 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -1,9 +1,16 @@ use crate::parser::Extractor; +use fxhash::FxHashSet; +use ignore::WalkBuilder; use rayon::prelude::*; +use std::cmp::Ordering; +use std::path::Path; use std::path::PathBuf; use tracing::event; +use walkdir::WalkDir; pub mod candidate; +pub mod cursor; +pub mod fast_skip; pub mod glob; pub mod location; pub mod modifier; @@ -11,14 +18,7 @@ pub mod parser; pub mod utility; pub mod variant; -#[derive(Debug, Clone)] -pub struct ChangedContent { - pub file: Option, - pub content: Option, - pub extension: String, -} - -pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { +fn init_tracing() { if matches!(std::env::var("DEBUG"), Ok(value) if value.eq("*") || value.eq("1") || value.eq("true") || value.contains("tailwind")) { tracing_subscriber::fmt() @@ -27,8 +27,325 @@ pub fn parse_candidate_strings_from_files(changed_content: Vec) .compact() .init(); } +} - parse_all_blobs(read_all_files(changed_content)) +#[derive(Debug, Clone)] +pub struct ChangedContent { + pub file: Option, + pub content: Option, + pub extension: String, +} + +#[derive(Debug, Clone)] +pub struct ContentPathInfo { + pub base: String, +} + +pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { + let root = Path::new(&args.base); + + let allowed_paths = FxHashSet::from_iter( + WalkBuilder::new(root) + .hidden(false) + .filter_entry(|entry| match entry.file_type() { + Some(file_type) if file_type.is_dir() => entry + .file_name() + .to_str() + .map(|s| s != ".git") + .unwrap_or(false), + _ => true, + }) + .build() + .filter_map(Result::ok) + .map(|x| x.into_path()), + ); + + // A list of directory names where we can't use globs, but we should track each file + // individually instead. This is because these directories are often used for both source and + // destination files. + let mut forced_static_directories = vec![root.join("public")]; + + // A list of known extensions + a list of extensions we found in the project. + let mut found_extensions = FxHashSet::from_iter( + include_str!("fixtures/template-extensions.txt") + .trim() + .lines() + .filter(|x| !x.starts_with('#')) // Drop commented lines + .filter(|x| !x.is_empty()) // Drop empty lines + .map(|x| x.to_string()), + ); + + // A list of static files that we should track directly. + let mut static_files = vec![]; + + // All root directories. + let mut root_directories = FxHashSet::from_iter(vec![root.to_path_buf()]); + + // All directories where we can safely use deeply nested globs to watch all files. + // In other comments we refer to these as "deep glob directories" or similar. + // + // E.g.: ./src/**/*.{html,js} + let mut deep_globable_directories: FxHashSet = FxHashSet::default(); + + // All directories where we can only use shallow globs to watch all direct files but not + // folders. + // In other comments we refer to these as "shallow glob directories" or similar. + // + // E.g.: ./src/*/*.{html,js} + let mut shallow_globable_directories: FxHashSet = FxHashSet::default(); + + // Collect all valid paths from the root. This will already filter out ignored files, unknown + // extensions and binary files. + let mut it = WalkDir::new(root) + // Sorting to make sure that we always see the directories before the files. Also sorting + // alphabetically by default. + .sort_by( + |a, z| match (a.file_type().is_dir(), z.file_type().is_dir()) { + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + _ => a.file_name().cmp(z.file_name()), + }, + ) + .into_iter(); + + loop { + // We are only interested in valid entries + let entry = match it.next() { + Some(Ok(entry)) => entry, + _ => break, + }; + + // Ignore known directories that we don't want to traverse into. + if entry.file_type().is_dir() && entry.file_name() == ".git" { + it.skip_current_dir(); + continue; + } + + if entry.file_type().is_dir() { + // If we are in a directory where we know that we can't use any globs, then we have to + // track each file individually. + if forced_static_directories.contains(&entry.path().to_path_buf()) { + forced_static_directories.push(entry.path().to_path_buf()); + root_directories.insert(entry.path().to_path_buf()); + continue; + } + + // If we are in a directory where the parent is a forced static directory, then this + // will become a forced static directory as well. + if forced_static_directories.contains(&entry.path().parent().unwrap().to_path_buf()) { + forced_static_directories.push(entry.path().to_path_buf()); + root_directories.insert(entry.path().to_path_buf()); + continue; + } + + // If we are in a directory, and the directory is git ignored, then we don't have to + // descent into the directory. However, we have to make sure that we mark the _parent_ + // directory as a shallow glob directory because using deep globs from any of the + // parent directories will include this ignored directory which should not be the case. + // + // Another important part is that if one of the ignored directories is a deep glob + // directory, then all of its parents (until the root) should be marked as shallow glob + // directories as well. + if !allowed_paths.contains(&entry.path().to_path_buf()) { + let mut parent = entry.path().parent(); + while let Some(parent_path) = parent { + // If the parent is already marked as a valid deep glob directory, then we have + // to mark it as a shallow glob directory instead, because we won't be able to + // use deep globs for this directory anymore. + if deep_globable_directories.contains(parent_path) { + deep_globable_directories.remove(parent_path); + shallow_globable_directories.insert(parent_path.to_path_buf()); + } + + // If we reached the root, then we can stop. + if parent_path == root { + break; + } + + // Mark the parent directory as a shallow glob directory and continue with its + // parent. + shallow_globable_directories.insert(parent_path.to_path_buf()); + parent = parent_path.parent(); + } + + it.skip_current_dir(); + continue; + } + // If we are in a directory that is not git ignored, then we can mark this directory as + // a valid deep glob directory. This is only necessary if any of its parents aren't + // marked as deep glob directories already. + else { + let mut found_deep_glob_parent = false; + let mut parent = entry.path().parent(); + while let Some(parent_path) = parent { + // If we reached the root, then we can stop. + if parent_path == root { + break; + } + + // If the parent is already marked as a deep glob directory, then we can stop + // because this glob will match the current directory already. + if deep_globable_directories.contains(parent_path) { + found_deep_glob_parent = true; + break; + } + + parent = parent_path.parent(); + } + + // If we didn't find a deep glob directory parent, then we can mark this directory + // as a deep glob directory (unless it is the root). + if !found_deep_glob_parent && entry.path() != root { + deep_globable_directories.insert(entry.path().to_path_buf()); + } + } + } + + // Handle allowed content paths + if is_allowed_content_path(entry.path()) + && allowed_paths.contains(&entry.path().to_path_buf()) + { + let path = entry.path(); + + // Collect the extension for future use when building globs. + if let Some(extension) = path.extension().and_then(|x| x.to_str()) { + found_extensions.insert(extension.to_string()); + } + + // If the current path is a file inside any of the root directories, then we have to + // track it directly as a static file. + if let Some(parent_path) = path.parent() { + if root_directories.contains(parent_path) { + static_files.push(format!("{}", path.display())); + } + } + } + } + + // Build the globs for all globable directories. + let shallow_globs = shallow_globable_directories + .iter() + .map(|path| format!("{}", path.display())); + let deep_globs = deep_globable_directories + .iter() + .map(|path| format!("{}/**", path.display())); + let globs = shallow_globs + .chain(deep_globs) + .flat_map(|path| match found_extensions.len() { + 0 => None, // This should never happen + 1 => Some(format!( + "{}/*.{}", + path, + found_extensions.iter().next().unwrap() + )), + _ => Some(format!( + "{}/*.{{{}}}", + path, + found_extensions + .iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + )), + }) + .collect::>(); + + static_files.extend(globs); + static_files +} + +pub fn is_git_ignored_content_path(base: &Path, path: &Path) -> bool { + !WalkBuilder::new(base) + .hidden(false) + .filter_entry(|entry| match entry.file_type() { + Some(file_type) if file_type.is_dir() => entry + .file_name() + .to_str() + .map(|s| s != ".git") + .unwrap_or(false), + _ => true, + }) + .build() + .filter_map(Result::ok) + .any(|e| e.path() == path) +} + +pub fn is_allowed_content_path(path: &Path) -> bool { + let binary_extensions = include_str!("fixtures/binary-extensions.txt") + .trim() + .lines() + .collect::>(); + let ignored_extensions = include_str!("fixtures/ignored-extensions.txt") + .trim() + .lines() + .collect::>(); + let ignored_files = include_str!("fixtures/ignored-files.txt") + .trim() + .lines() + .collect::>(); + + let path = PathBuf::from(path); + + // Skip known ignored files + if path + .file_name() + .unwrap() + .to_str() + .map(|s| ignored_files.contains(&s)) + .unwrap_or(false) + { + return false; + } + + // Skip known ignored extensions + return path + .extension() + .map(|s| s.to_str().unwrap_or_default()) + .map(|ext| !ignored_extensions.contains(&ext) && !binary_extensions.contains(&ext)) + .unwrap_or(false); +} + +#[derive(Debug)] +pub enum IO { + Sequential = 0b0001, + Parallel = 0b0010, +} + +impl From for IO { + fn from(item: u8) -> Self { + match item & 0b0011 { + 0b0001 => IO::Sequential, + 0b0010 => IO::Parallel, + _ => unimplemented!("Unknown 'IO' strategy"), + } + } +} + +#[derive(Debug)] +pub enum Parsing { + Sequential = 0b0100, + Parallel = 0b1000, +} + +impl From for Parsing { + fn from(item: u8) -> Self { + match item & 0b1100 { + 0b0100 => Parsing::Sequential, + 0b1000 => Parsing::Parallel, + _ => unimplemented!("Unknown 'Parsing' strategy"), + } + } +} + +pub fn parse_candidate_strings(input: Vec, options: u8) -> Vec { + init_tracing(); + + match (IO::from(options), Parsing::from(options)) { + (IO::Sequential, Parsing::Sequential) => parse_all_blobs_sync(read_all_files_sync(input)), + (IO::Sequential, Parsing::Parallel) => parse_all_blobs_sync(read_all_files(input)), + (IO::Parallel, Parsing::Sequential) => parse_all_blobs(read_all_files_sync(input)), + (IO::Parallel, Parsing::Parallel) => parse_all_blobs(read_all_files(input)), + } } #[tracing::instrument(skip(changed_content))] @@ -41,6 +358,30 @@ fn read_all_files(changed_content: Vec) -> Vec> { changed_content .into_par_iter() + .map(|c| match (c.file, c.content) { + (Some(file), None) => match std::fs::read(file) { + Ok(content) => content, + Err(e) => { + event!(tracing::Level::ERROR, "Failed to read file: {:?}", e); + Default::default() + } + }, + (None, Some(content)) => content.into_bytes(), + _ => Default::default(), + }) + .collect() +} + +#[tracing::instrument(skip(changed_content))] +fn read_all_files_sync(changed_content: Vec) -> Vec> { + event!( + tracing::Level::INFO, + "Reading {:?} file(s)", + changed_content.len() + ); + + changed_content + .into_iter() .map(|c| match (c.file, c.content) { (Some(file), None) => std::fs::read(file).unwrap(), (None, Some(content)) => content.into_bytes(), @@ -72,3 +413,27 @@ fn parse_all_blobs(blobs: Vec>) -> Vec { result.sort(); result } + +#[tracing::instrument(skip(blobs))] +fn parse_all_blobs_sync(blobs: Vec>) -> Vec { + let input: Vec<_> = blobs.iter().map(|blob| &blob[..]).collect(); + let input = &input[..]; + + let mut result: Vec = input + .iter() + .map(|input| Extractor::unique(input, Default::default())) + .fold(FxHashSet::default(), |mut a, b| { + a.extend(b); + a + }) + .into_iter() + .map(|s| { + // SAFETY: When we parsed the candidates, we already guaranteed that the byte slices + // are valid, therefore we don't have to re-check here when we want to convert it back + // to a string. + unsafe { String::from_utf8_unchecked(s.to_vec()) } + }) + .collect(); + result.sort(); + result +} diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index 16831afff..764800f0f 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -2,6 +2,39 @@ use bstr::ByteSlice; use fxhash::FxHashSet; use tracing::trace; +use crate::{cursor::Cursor, fast_skip::fast_skip}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ParseAction<'a> { + Consume, + Skip, + RestartAt(usize), + + SingleCandidate(&'a [u8]), + MultipleCandidates(Vec<&'a [u8]>), + Done, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Bracketing<'a> { + Included(&'a [u8]), + Wrapped(&'a [u8]), + None, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct SplitCandidate<'a> { + variant: &'a [u8], + utility: &'a [u8], +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum ValidationResult { + Invalid, + Valid, + Restart, +} + #[derive(Default)] pub struct ExtractorOptions { pub preserve_spaces_in_arbitrary: bool, @@ -11,9 +44,7 @@ pub struct Extractor<'a> { opts: ExtractorOptions, input: &'a [u8], - pos: usize, - - prev: u8, + cursor: Cursor<'a>, idx_start: usize, idx_end: usize, @@ -24,24 +55,24 @@ pub struct Extractor<'a> { in_candidate: bool, in_escape: bool, + discard_next: bool, + quote_stack: Vec, bracket_stack: Vec, - // buffer: [Option<&'a [u8]>; 8], } impl<'a> Extractor<'a> { pub fn all(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { - Self::new(input, opts).into_iter().collect() + Self::new(input, opts).flatten().collect() } pub fn unique(input: &'a [u8], opts: ExtractorOptions) -> FxHashSet<&'a [u8]> { let mut candidates: FxHashSet<&[u8]> = Default::default(); candidates.reserve(100); - candidates.extend(Self::new(input, opts).into_iter()); + candidates.extend(Self::new(input, opts).flatten()); candidates } - #[cfg(test)] pub fn unique_ord(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { // This is an inefficient way to get an ordered, unique // list as a Vec but it is only meant for testing. @@ -59,8 +90,7 @@ impl<'a> Extractor<'a> { Self { opts, input, - pos: 0, - prev: 0, + cursor: Cursor::new(input), idx_start: 0, idx_end: 0, @@ -70,10 +100,11 @@ impl<'a> Extractor<'a> { in_candidate: false, in_escape: false, + discard_next: false, + idx_last: input.len(), quote_stack: Vec::with_capacity(8), bracket_stack: Vec::with_capacity(8), - // buffer: [None; 8], } } } @@ -86,126 +117,222 @@ impl<'a> Extractor<'a> { } #[inline(always)] - fn get_current_candidate(&mut self) -> Option<&'a [u8]> { - let candidate = &self.input[self.idx_start..=self.idx_end]; + fn get_current_candidate(&mut self) -> ParseAction<'a> { + if self.discard_next { + return ParseAction::Skip; + } - if Extractor::is_valid_candidate_string(candidate) { - Some(candidate) - } else { - None + let mut candidate = &self.input[self.idx_start..=self.idx_end]; + + while !candidate.is_empty() { + match Extractor::is_valid_candidate_string(candidate) { + ValidationResult::Valid => return ParseAction::SingleCandidate(candidate), + ValidationResult::Restart => return ParseAction::RestartAt(self.idx_start + 1), + _ => {} + } + + match candidate.split_last() { + // At this point the candidate is technically invalid, however it can be that it + // has a few dangling characters attached to it. For example, think about a + // JavaScript object: + // + // ```js + // { underline: true } + // ``` + // + // The candidate at this point will be `underline:`, which is invalid. However, we + // can assume in this case that the `:` should not be there, and therefore we can + // try to slice it off and retry the validation. + Some((b':' | b'/' | b'.', head)) => { + candidate = head; + } + + // It could also be that we have the candidate is nested inside of bracket or quote + // pairs. In this case we want to retrieve the inner part and try to validate that + // inner part instead. For example, in a JavaScript array: + // + // ```js + // let myClasses = ["underline"] + // ``` + // + // The `underline` is nested inside of quotes and in square brackets. Let's try to + // get the inner part and validate that instead. + _ => match Self::slice_surrounding(candidate) { + Some(shorter) if shorter != candidate => { + candidate = shorter; + } + _ => break, + }, + } + } + + ParseAction::Consume + } + + #[inline(always)] + fn split_candidate(candidate: &'a [u8]) -> SplitCandidate { + let mut brackets = 0; + let mut idx_end = 0; + + for (n, c) in candidate.iter().enumerate() { + match c { + b'[' => brackets += 1, + b']' if brackets > 0 => brackets -= 1, + b':' if brackets == 0 => idx_end = n + 1, + _ => {} + } + } + + SplitCandidate { + variant: &candidate[0..idx_end], + utility: &candidate[idx_end..], } } #[inline(always)] - fn is_valid_candidate_string(candidate: &'a [u8]) -> bool { - let original_candidate = &candidate; - let mut offset = 0; + fn contains_in_constrained(candidate: &'a [u8], bytes: Vec) -> bool { + let mut brackets = 0; - // Some special cases that we can ignore while testing the validations. - if candidate.starts_with(b"!-") { + for c in candidate { + match c { + b'[' => brackets += 1, + b']' if brackets > 0 => brackets -= 1, + _ if brackets == 0 && bytes.contains(c) => return true, + _ => {} + } + } + + false + } + + #[inline(always)] + fn is_valid_candidate_string(candidate: &'a [u8]) -> ValidationResult { + let split_candidate = Extractor::split_candidate(candidate); + + let mut offset = 0; + let utility = &split_candidate.utility; + let original_utility = &utility; + + // Some special cases that we can ignore while validating + if utility.starts_with(b"!-") { offset += 2; - } else if candidate.starts_with(b"!") || candidate.starts_with(b"-") { + } else if utility.starts_with(b"!") || utility.starts_with(b"-") { offset += 1; } + // These are allowed in arbitrary values and in variants but nowhere else + if Extractor::contains_in_constrained(utility, vec![b'<', b'>']) { + return ValidationResult::Restart; + } + + // It's an arbitrary property + if utility.starts_with(b"[") + && utility.ends_with(b"]") + && (utility.starts_with(b"['") + || utility.starts_with(b"[\"") + || utility.starts_with(b"[`")) + { + return ValidationResult::Restart; + } + // Pluck out the part that we are interested in. - let candidate = &candidate[offset..]; + let utility = &utility[offset..]; // Validations // We should have _something_ - if candidate.is_empty() { - return false; + if utility.is_empty() { + return ValidationResult::Invalid; } // = b'0' && candidate[0] <= b'9' && !candidate.contains(&b':') { - return false; + if utility[0] >= b'0' && utility[0] <= b'9' && !utility.contains(&b':') { + return ValidationResult::Invalid; } // In case of an arbitrary property, we should have at least this structure: [a:b] - if candidate.starts_with(b"[") && candidate.ends_with(b"]") { + if utility.starts_with(b"[") && utility.ends_with(b"]") { // [a:b] is at least 5 characters long - if candidate.len() < 5 { - return false; + if utility.len() < 5 { + return ValidationResult::Invalid; } // Should contain a `:` - if !candidate.contains(&b':') { - return false; + if !utility.contains(&b':') { + return ValidationResult::Invalid; } // Now that we validated that the candidate is technically fine, let's ensure that it // doesn't start with a `-` because that would make it invalid for arbitrary properties. - if original_candidate.starts_with(b"-") || original_candidate.starts_with(b"!-") { - return false; + if original_utility.starts_with(b"-") || original_utility.starts_with(b"!-") { + return ValidationResult::Invalid; } // The ':` must be preceded by a-Z0-9 because it represents a property name. - let colon = candidate.find(":").unwrap(); + let colon = utility.find(":").unwrap(); - if !candidate + if !utility .chars() .nth(colon - 1) .map_or_else(|| false, |c| c.is_ascii_alphanumeric()) { - return false; + return ValidationResult::Invalid; } } // In case of an arbitrary property, we should not have a modifier of any kind - if candidate.starts_with(b"[") { + if utility.starts_with(b"[") { if let Some(first_non_escaped_closing_bracket_idx) = - candidate.char_indices().position(|(s, _, other)| { + utility.char_indices().position(|(s, _, other)| { other == ']' - && candidate + && utility .get((s - 1)..s) .map(|c| !c.eq(b"\\")) .unwrap_or(false) }) { - if let Some(next) = candidate + if let Some(next) = utility .chars() .nth(first_non_escaped_closing_bracket_idx + 1) { // `/` is the indicator for a modifier, this is not allowed after arbitrary // properties if next == '/' { - return false; + return ValidationResult::Invalid; } } } } - true + ValidationResult::Valid } #[inline(always)] - fn parse_escaped(&mut self) -> bool { + fn parse_escaped(&mut self) -> ParseAction<'a> { // If this character is escaped, we don't care about it. // It gets consumed. trace!("Escape::Consume"); self.in_escape = false; - true + ParseAction::Consume } #[inline(always)] - fn parse_arbitrary(&mut self, curr: u8, pos: usize) -> bool { + fn parse_arbitrary(&mut self) -> ParseAction<'a> { // In this we could technically use memchr 6 times (then looped) to find the indexes / bounds of arbitrary valuesq if self.in_escape { return self.parse_escaped(); } - match curr { + match self.cursor.curr { b'\\' => { // The `\` character is used to escape characters in arbitrary content _and_ to prevent the starting of arbitrary content trace!("Arbitrary::Escape"); @@ -213,7 +340,7 @@ impl<'a> Extractor<'a> { } // Make sure the brackets are balanced - b'[' => self.bracket_stack.push(curr), + b'[' => self.bracket_stack.push(self.cursor.curr), b']' => match self.bracket_stack.last() { // We've ended a nested bracket Some(&last_bracket) if last_bracket == b'[' => { @@ -222,12 +349,16 @@ impl<'a> Extractor<'a> { // This is the last bracket meaning the end of arbitrary content _ if !self.in_quotes() => { + if matches!(self.cursor.next, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9') { + return ParseAction::Consume; + } + trace!("Arbitrary::End\t"); self.in_arbitrary = false; - if pos - self.idx_arbitrary_start == 1 { + if self.cursor.pos - self.idx_arbitrary_start == 1 { // We have an empty arbitrary value, which is not allowed - return false; + return ParseAction::Skip; } } @@ -239,19 +370,22 @@ impl<'a> Extractor<'a> { // These can "escape" the arbitrary value mode // switching of `[` and `]` characters b'"' | b'\'' | b'`' => match self.quote_stack.last() { - Some(&last_quote) if last_quote == curr => { + Some(&last_quote) if last_quote == self.cursor.curr => { trace!("Quote::End\t"); self.quote_stack.pop(); } _ => { trace!("Quote::Start\t"); - self.quote_stack.push(curr); + self.quote_stack.push(self.cursor.curr); } }, b' ' if !self.opts.preserve_spaces_in_arbitrary => { trace!("Arbitrary::SkipAndEndEarly\t"); - return false; + + // Restart the parser ahead of the arbitrary value + // It may pick up more candidates + return ParseAction::RestartAt(self.idx_arbitrary_start + 1); } // Arbitrary values allow any character inside them @@ -262,51 +396,55 @@ impl<'a> Extractor<'a> { } } - true + ParseAction::Consume } #[inline(always)] - fn parse_start(&mut self, curr: u8, pos: usize) -> bool { - match curr { + fn parse_start(&mut self) -> ParseAction<'a> { + match self.cursor.curr { // Enter arbitrary value mode b'[' => { trace!("Arbitrary::Start\t"); self.in_arbitrary = true; - self.idx_arbitrary_start = pos; + self.idx_arbitrary_start = self.cursor.pos; - true + ParseAction::Consume } // Allowed first characters. - b'@' | b'!' | b'-' | b'<' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => { + b'@' | b'!' | b'-' | b'<' | b'>' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => { // TODO: A bunch of characters that we currently support but maybe we only want it behind // a flag. E.g.: '' | '$' | '^' | '_' + // | '$' | '^' | '_' + + // When the new candidate is preceeded by a `:`, then we want to keep parsing, but + // throw away the full candidate because it can not be a valid candidate at the end + // of the day. + if self.cursor.prev == b':' { + self.discard_next = true; + } trace!("Candidate::Start\t"); - true + ParseAction::Consume } - _ => false, + _ => ParseAction::Skip, } } #[inline(always)] - fn parse_continue(&mut self, prev: u8, curr: u8, pos: usize) -> bool { - match curr { + fn parse_continue(&mut self) -> ParseAction<'a> { + match self.cursor.curr { // Enter arbitrary value mode - b'[' if prev == b'@' - || prev == b'-' - || prev == b' ' - || prev == b':' // Variant separator - || prev == b'/' // Modifier separator - || prev == b'!' - || prev == b'\0' => + b'[' if matches!( + self.cursor.prev, + b'@' | b'-' | b' ' | b':' | b'/' | b'!' | b'\0' + ) => { trace!("Arbitrary::Start\t"); self.in_arbitrary = true; - self.idx_arbitrary_start = pos; + self.idx_arbitrary_start = self.cursor.pos; } // Can't enter arbitrary value mode @@ -314,154 +452,305 @@ impl<'a> Extractor<'a> { b'[' => { trace!("Arbitrary::Skip_Start\t"); - return false; + return ParseAction::Skip; + } + + // A % can only appear at the end of the candidate itself. It can also only be after a + // digit 0-9. This covers the following cases: + // - from-15% + b'%' if self.cursor.prev.is_ascii_digit() => { + return match (self.cursor.at_end, self.cursor.next) { + // End of string == end of candidate == okay + (true, _) => ParseAction::Consume, + + // Looks like the end of a candidate == okay + (_, b' ' | b'\'' | b'"' | b'`') => ParseAction::Consume, + + // Otherwise, not a valid character in a candidate + _ => ParseAction::Skip, + }; + } + b'%' => return ParseAction::Skip, + + // < and > can only be part of a variant and only be the first or last character + b'<' | b'>' => { + // Can only be the first or last character + // E.g.: + // - :underline + // ^ + if self.cursor.pos == self.idx_start || self.cursor.pos == self.idx_last { + trace!("Candidate::Consume\t"); + } + // If it is in the middle, it can only be part of a stacked variant + // - dark::underline + // ^ + else if self.cursor.prev == b':' || self.cursor.next == b':' { + trace!("Candidate::Consume\t"); + } else { + return ParseAction::Skip; + } } // Allowed characters in the candidate itself // None of these can come after a closing bracket `]` - b'a'..=b'z' - | b'A'..=b'Z' - | b'0'..=b'9' - | b'-' - | b'_' - | b'(' - | b')' - | b'!' - | b'@' - | b'%' - if prev != b']' => + b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'-' | b'_' | b'!' | b'@' + if self.cursor.prev != b']' => { /* TODO: The `b'@'` is necessary for custom separators like _@, maybe we can handle this in a better way... */ trace!("Candidate::Consume\t"); } + // A dot (.) can only appear in the candidate itself (not the arbitrary part), if the previous + // and next characters are both digits. This covers the following cases: + // - p-1.5 + b'.' if self.cursor.prev.is_ascii_digit() => match self.cursor.next { + next if next.is_ascii_digit() => { + trace!("Candidate::Consume\t"); + } + _ => return ParseAction::Skip, + }, + // Allowed characters in the candidate itself // These MUST NOT appear at the end of the candidate - b'/' | b':' | b'.' if pos + 1 < self.idx_last => { + b'/' | b':' if !self.cursor.at_end => { trace!("Candidate::Consume\t"); } - _ => return false, + _ => return ParseAction::Skip, } - true + ParseAction::Consume } #[inline(always)] - fn can_be_candidate(&mut self, c: u8) -> bool { + fn can_be_candidate(&mut self) -> bool { self.in_candidate && !self.in_arbitrary - && (0..=127).contains(&c) - && (self.idx_start == 0 || self.input[(self.idx_start - 1)] <= 127) + && (0..=127).contains(&self.cursor.curr) + && (self.idx_start == 0 || self.input[self.idx_start - 1] <= 127) } #[inline(always)] - fn handle_skip(&mut self, pos: usize) { + fn handle_skip(&mut self) { // In all other cases, we skip characters and reset everything so we can make new candidates trace!("Characters::Skip\t"); - self.idx_start = pos; - self.idx_end = pos; + self.idx_start = self.cursor.pos; + self.idx_end = self.cursor.pos; self.in_candidate = false; self.in_arbitrary = false; self.in_escape = false; } #[inline(always)] - fn parse_char(&mut self, prev: u8, curr: u8, pos: usize) -> bool { + fn parse_char(&mut self) -> ParseAction<'a> { if self.in_arbitrary { - self.parse_arbitrary(curr, pos) + self.parse_arbitrary() } else if self.in_candidate { - self.parse_continue(prev, curr, pos) - } else if self.parse_start(curr, pos) { + self.parse_continue() + } else if self.parse_start() == ParseAction::Consume { self.in_candidate = true; - self.idx_start = pos; - self.idx_end = pos; + self.idx_start = self.cursor.pos; + self.idx_end = self.cursor.pos; - true + ParseAction::Consume } else { - false + ParseAction::Skip } } #[inline(always)] - fn yield_candidate(&mut self, pos: usize, curr: u8, did_consume: bool) -> Option<&'a [u8]> { - // If we're still consuming characters, we keep going - // Only exception is if we've hit the end of the input - if did_consume && pos + 1 < self.idx_last { - return None; - } - - let candidate = if self.can_be_candidate(curr) { + fn yield_candidate(&mut self) -> ParseAction<'a> { + if self.can_be_candidate() { self.get_current_candidate() } else { - None - }; - - self.handle_skip(pos); - - candidate + ParseAction::Consume + } } #[inline(always)] - fn read(&mut self) -> (usize, u8) { - if self.pos == self.idx_last { - return (usize::MAX, 0); - } + fn restart(&mut self, pos: usize) { + trace!("Parser::Restart\t{}", pos); - let r = (self.pos, self.input[self.pos]); - self.pos += 1; + self.idx_start = pos; + self.idx_end = pos; + self.idx_arbitrary_start = 0; - r + self.in_arbitrary = false; + self.in_candidate = false; + self.in_escape = false; + + self.discard_next = false; + + self.quote_stack.clear(); + self.bracket_stack.clear(); + self.cursor.move_to(pos); } #[inline(always)] - fn parse_and_yield(&mut self) -> Option> { - let (pos, curr) = self.read(); - let did_consume = self.parse_char(self.prev, curr, pos); + fn without_surrounding(&self) -> Bracketing<'a> { + let range = self.idx_start..=self.idx_end; + let clipped = &self.input[range]; - if did_consume { - self.idx_end = pos; + Self::slice_surrounding(clipped) + .map(Bracketing::Included) + .or_else(|| { + if self.idx_start == 0 || self.idx_end + 1 == self.idx_last { + return None; + } + + let range = self.idx_start - 1..=self.idx_end + 1; + let clipped = &self.input[range]; + Self::slice_surrounding(clipped).map(Bracketing::Wrapped) + }) + .unwrap_or(Bracketing::None) + } + + #[inline(always)] + fn is_balanced(input: &[u8]) -> bool { + let mut depth = 0isize; + + for n in input { + match n { + b'[' | b'{' | b'(' => depth += 1, + b']' | b'}' | b')' => depth -= 1, + _ => continue, + } + + if depth < 0 { + return false; + } } - let candidate = self.yield_candidate(pos, curr, did_consume); - self.prev = curr; + depth == 0 + } - if curr == 0 { - None - } else { - Some(candidate) + #[inline(always)] + fn slice_surrounding(input: &[u8]) -> Option<&[u8]> { + let mut prev = None; + let mut input = input; + + loop { + let leading = input.first().unwrap_or(&0x00); + let trailing = input.last().unwrap_or(&0x00); + + let needed = matches!( + (leading, trailing), + (b'(', b')') + | (b'{', b'}') + | (b'[', b']') + | (b'"', b'"') + | (b'`', b'`') + | (b'\'', b'\'') + ); + + if needed { + prev = Some(input); + input = &input[1..input.len() - 1]; + continue; + } else if Self::is_balanced(input) && prev.is_some() { + return Some(input); + } else { + return prev; + } + } + } + + #[inline(always)] + fn parse_and_yield(&mut self) -> ParseAction<'a> { + trace!("Cursor {}", self.cursor); + + // Fast skipping of invalid characters + let can_skip_whitespace = false; // if self.opts.preserve_spaces_in_arbitrary { !self.in_arbitrary } else { true }; + if can_skip_whitespace { + if let Some(pos) = fast_skip(&self.cursor) { + trace!("FastSkip::Restart\t{}", pos); + return ParseAction::RestartAt(pos); + } + } + + let action = self.parse_char(); + + match action { + ParseAction::RestartAt(_) => return action, + ParseAction::Consume => { + self.idx_end = self.cursor.pos; + + // If we're still consuming characters, we keep going + // Only exception is if we've hit the end of the input + if !self.cursor.at_end { + return action; + } + } + _ => {} + } + + let action = self.yield_candidate(); + + match (&action, self.cursor.curr) { + (ParseAction::RestartAt(_), _) => action, + (_, 0x00) => ParseAction::Done, + (ParseAction::SingleCandidate(candidate), _) => self.generate_slices(candidate), + _ => ParseAction::RestartAt(self.cursor.pos + 1), + } + } + + /// Peek inside `[]`, `{}`, and `()` pairs + /// to look for an additional candidate + #[inline(always)] + fn generate_slices(&mut self, candidate: &'a [u8]) -> ParseAction<'a> { + match self.without_surrounding() { + Bracketing::None => ParseAction::SingleCandidate(candidate), + Bracketing::Included(slicable) if slicable == candidate => { + ParseAction::SingleCandidate(candidate) + } + Bracketing::Included(slicable) | Bracketing::Wrapped(slicable) => { + let parts = vec![candidate, slicable]; + let parts = parts + .into_iter() + .filter(|v| !v.is_empty()) + .collect::>(); + + ParseAction::MultipleCandidates(parts) + } } } } impl<'a> Iterator for Extractor<'a> { - type Item = &'a [u8]; + type Item = Vec<&'a [u8]>; fn next(&mut self) -> Option { - if self.pos == self.idx_last { + if self.cursor.at_end { return None; } loop { - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; + let result = self.parse_and_yield(); + + // Cursor control + match result { + ParseAction::RestartAt(pos) => self.restart(pos), + _ => self.cursor.advance_by(1), } - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; + // Candidate state control + match result { + ParseAction::SingleCandidate(_) => self.handle_skip(), + ParseAction::MultipleCandidates(_) => self.handle_skip(), + _ => {} } - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; - } - - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; - } + // Iterator results + return match result { + ParseAction::SingleCandidate(candidate) => Some(vec![candidate]), + ParseAction::MultipleCandidates(candidates) => Some(candidates), + ParseAction::Done => None, + _ => continue, + }; } } } @@ -470,7 +759,7 @@ impl<'a> Iterator for Extractor<'a> { mod test { use super::*; - fn please_trace() { + fn _please_trace() { tracing_subscriber::fmt() .with_max_level(tracing::Level::TRACE) .with_span_events(tracing_subscriber::fmt::format::FmtSpan::ACTIVE) @@ -542,8 +831,7 @@ mod test { fn it_should_not_keep_spaces() { let candidates = run("bg-[rgba(0, 0, 0)]", false); - // TODO: This should be empty, because the arbitrary value is unbalanced. - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["rgba"]); } #[test] @@ -564,7 +852,7 @@ mod test { assert!(candidates.is_empty()); let candidates = run("[something]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["something"]); let candidates = run("[color:red]/dark", false); assert!(candidates.is_empty()); @@ -573,7 +861,7 @@ mod test { assert!(candidates.is_empty()); let candidates = run(" [feature(slice_as_chunks)]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["feature(slice_as_chunks)"]); let candidates = run("![feature(slice_as_chunks)]", false); assert!(candidates.is_empty()); @@ -632,6 +920,7 @@ mod test { assert_eq!( candidates, vec![ + "div", "class", r#"dark:lg:hover:[&>*]:underline"#, r#"[&_.foo\_\_bar]:hover:underline"#, @@ -646,7 +935,7 @@ mod test { assert_eq!( candidates, vec![ - // "p", // TODO: This is missing. Maybe? + "p", "class", "text-sm", "text-blue-700", @@ -655,22 +944,22 @@ mod test { "software", "update", "is", - "available.", + "available", "See", // "what", // what is dropped because it is followed by the fancy: ’ // "s", // s is dropped because it is preceeded by the fancy: ’ // "new", // Already seen "in", "version", - "p", // Hmm, becuse "

" ] ); } #[test] fn ignores_arbitrary_property_ish_things() { + // FIXME: () are only valid in an arbitrary let candidates = run(" [feature(slice_as_chunks)]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["feature(slice_as_chunks)",]); } #[test] @@ -697,7 +986,7 @@ mod test { #[test] fn bad_001() { let candidates = run("[杛杛]/", false); - assert!(candidates.is_empty()) + assert_eq!(candidates, vec!["杛杛"]); } #[test] @@ -708,7 +997,139 @@ mod test { #[test] fn bad_003() { + // TODO: This seems… wrong let candidates = run(r"[𕤵:]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["𕤵", "𕤵:"]); + } + + #[test] + fn classes_in_js_arrays() { + let candidates = run( + r#"let classes = ['bg-black', 'hover:px-0.5', 'text-[13px]', '[--my-var:1_/_2]', '[.foo_&]:px-[0]', '[.foo_&]:[color:red]']">"#, + false, + ); + assert_eq!( + candidates, + vec![ + "let", + "classes", + "bg-black", + "hover:px-0.5", + "text-[13px]", + "[--my-var:1_/_2]", + "--my-var:1_/_2", + "[.foo_&]:px-[0]", + "[.foo_&]:[color:red]", + ] + ); + } + + #[test] + fn classes_in_js_arrays_without_spaces() { + let candidates = run( + r#"let classes = ['bg-black','hover:px-0.5','text-[13px]','[--my-var:1_/_2]','[.foo_&]:px-[0]','[.foo_&]:[color:red]']">"#, + false, + ); + assert_eq!( + candidates, + vec![ + "let", + "classes", + "bg-black", + "hover:px-0.5", + "text-[13px]", + "[--my-var:1_/_2]", + "--my-var:1_/_2", + "[.foo_&]:px-[0]", + "[.foo_&]:[color:red]", + ] + ); + } + + #[test] + fn classes_as_object_keys() { + let candidates = run( + r#"
"#, + false, + ); + assert_eq!( + candidates, + vec!["div", "underline", "isActive", "px-1.5", "isOnline"] + ); + } + + #[test] + fn multiple_nested_candidates() { + let candidates = run(r#"{color:red}"#, false); + assert_eq!(candidates, vec!["color:red"]); + } + + #[test] + fn percent_ended_candidates() { + let candidates = run( + r#""#, + false, + ); + assert_eq!( + candidates, + vec![ + "!--", + "This", + "should", + "work", + "underline", + "from-50%", + "flex", + "--" + ] + ); + } + + #[test] + fn ruby_percent_formatted_strings() { + let candidates = run(r#"%w[hover:flex]"#, false); + assert_eq!(candidates, vec!["w", "hover:flex"]); + } + + #[test] + fn candidate_slicing() { + let result = Extractor::slice_surrounding(&b".foo_&]:px-[0"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, None); + + let result = Extractor::slice_surrounding(&b"[.foo_&]:px-[0]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); + + let result = Extractor::slice_surrounding(&b"{[.foo_&]:px-[0]}"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); + + let result = Extractor::slice_surrounding(&b"![foo:bar]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, None); + + let result = Extractor::slice_surrounding(&b"[\"pt-1.5\"]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("pt-1.5")); + + let count = 1_000; + let crazy = format!("{}[.foo_&]:px-[0]{}", "[".repeat(count), "]".repeat(count)); + + let result = Extractor::slice_surrounding(crazy.as_bytes()) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); } } diff --git a/oxide/crates/core/tests/auto_content.rs b/oxide/crates/core/tests/auto_content.rs new file mode 100644 index 000000000..f7a185f6c --- /dev/null +++ b/oxide/crates/core/tests/auto_content.rs @@ -0,0 +1,248 @@ +#[cfg(test)] +mod auto_content { + use std::fs; + use std::process::Command; + + use tailwindcss_core::*; + use tempfile::tempdir; + + fn test(paths_with_content: &[(&str, Option<&str>)]) -> Vec { + // Create a temporary working directory + let dir = tempdir().unwrap().into_path(); + + // Initialize this directory as a git repository + let _ = Command::new("git").arg("init").current_dir(&dir).output(); + + // Create the necessary files + for (path, contents) in paths_with_content { + let path = dir.join(path); + let parent = path.parent().unwrap(); + if !parent.exists() { + fs::create_dir_all(parent).unwrap(); + } + + match contents { + Some(contents) => fs::write(path, contents).unwrap(), + None => fs::write(path, "").unwrap(), + } + } + + let base = format!("{}", dir.display()); + + // Resolve all content paths for the (temporary) current working directory + let mut paths: Vec<_> = resolve_content_paths(ContentPathInfo { base: base.clone() }) + .into_iter() + .map(|x| x.replace(&format!("{}/", &base), "")) + .collect(); + + // Sort the output for easier comparison (depending on internal datastructure the order + // _could_ be random) + paths.sort(); + + paths + } + + #[test] + fn it_should_work_with_a_set_of_root_files() { + let globs = test(&[ + ("index.html", None), + ("a.html", None), + ("b.html", None), + ("c.html", None), + ]); + assert_eq!(globs, vec!["a.html", "b.html", "c.html", "index.html"]); + } + + #[test] + fn it_should_work_with_a_set_of_root_files_and_ignore_ignored_files() { + let globs = test(&[ + (".gitignore", Some("b.html")), + ("index.html", None), + ("a.html", None), + ("b.html", None), + ("c.html", None), + ]); + assert_eq!(globs, vec!["a.html", "c.html", "index.html"]); + } + + #[test] + fn it_should_list_all_files_in_the_public_folder_explicitly() { + let globs = test(&[ + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ]); + assert_eq!( + globs, + vec![ + "index.html", + "public/a.html", + "public/b.html", + "public/c.html", + ] + ); + } + + #[test] + fn it_should_list_nested_folders_explicitly_in_the_public_folder() { + let globs = test(&[ + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ("public/nested/a.html", None), + ("public/nested/b.html", None), + ("public/nested/c.html", None), + ("public/nested/again/a.html", None), + ("public/very/deeply/nested/a.html", None), + ]); + assert_eq!( + globs, + vec![ + "index.html", + "public/a.html", + "public/b.html", + "public/c.html", + "public/nested/a.html", + "public/nested/again/a.html", + "public/nested/b.html", + "public/nested/c.html", + "public/very/deeply/nested/a.html", + ] + ); + } + + #[test] + fn it_should_list_all_files_in_the_public_folder_explicitly_except_ignored_files() { + let globs = test(&[ + (".gitignore", Some("public/b.html\na.html")), + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ]); + assert_eq!(globs, vec!["index.html", "public/c.html",]); + } + + #[test] + fn it_should_use_a_glob_for_top_level_folders() { + let globs = test(&[ + ("index.html", None), + ("src/a.html", None), + ("src/b.html", None), + ("src/c.html", None), + ]); + assert_eq!(globs, vec!["index.html", "src/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}"]); + } + + #[test] + fn it_should_ignore_binary_files() { + let globs = test(&[ + ("index.html", None), + ("a.mp4", None), + ("b.png", None), + ("c.lock", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_known_extensions() { + let globs = test(&[ + ("index.html", None), + ("a.css", None), + ("b.sass", None), + ("c.less", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_known_files() { + let globs = test(&[ + ("index.html", None), + ("package-lock.json", None), + ("yarn.lock", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_and_expand_nested_ignored_folders() { + let globs = test(&[ + // Explicitly listed root files + ("foo.html", None), + ("bar.html", None), + ("baz.html", None), + // Nested folder A, using glob + ("nested-a/foo.html", None), + ("nested-a/bar.html", None), + ("nested-a/baz.html", None), + // Nested folder B, with deeply nested files, using glob + ("nested-b/deeply-nested/foo.html", None), + ("nested-b/deeply-nested/bar.html", None), + ("nested-b/deeply-nested/baz.html", None), + // Nested folder C, with ignored sub-folder + ("nested-c/foo.html", None), + ("nested-c/bar.html", None), + ("nested-c/baz.html", None), + // Ignored folder + ("nested-c/.gitignore", Some("ignored-folder/")), + ("nested-c/ignored-folder/foo.html", None), + ("nested-c/ignored-folder/bar.html", None), + ("nested-c/ignored-folder/baz.html", None), + // Deeply nested, without issues + ("nested-c/sibling-folder/foo.html", None), + ("nested-c/sibling-folder/bar.html", None), + ("nested-c/sibling-folder/baz.html", None), + // Nested folder D, with deeply nested ignored folder + ("nested-d/foo.html", None), + ("nested-d/bar.html", None), + ("nested-d/baz.html", None), + ("nested-d/.gitignore", Some("deep/")), + ("nested-d/very/deeply/nested/deep/foo.html", None), + ("nested-d/very/deeply/nested/deep/bar.html", None), + ("nested-d/very/deeply/nested/deep/baz.html", None), + ("nested-d/very/deeply/nested/foo.html", None), + ("nested-d/very/deeply/nested/bar.html", None), + ("nested-d/very/deeply/nested/baz.html", None), + ("nested-d/very/deeply/nested/directory/foo.html", None), + ("nested-d/very/deeply/nested/directory/bar.html", None), + ("nested-d/very/deeply/nested/directory/baz.html", None), + ("nested-d/very/deeply/nested/directory/again/foo.html", None), + ]); + + assert_eq!( + globs, + vec![ + // Listed explicitly because they are in the root + "bar.html", + "baz.html", + "foo.html", + + // Listed using a deep glob, because nothing inside is ignored + "nested-a/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Listed using a deep glob, because nothing inside is ignored (but contains deeply + // nested folders) + "nested-b/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Listed using a shallow glob, because `nested-c` contains ignored folders, deeply + // nested globs can't be used anymore + "nested-c/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Deeply nested folder can use a deep glob again + "nested-c/sibling-folder/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // The deeply nested folder can use a deep glob, however all of its parents can + // only contain a shallow glob because of the ignored folder + "nested-d/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/nested/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/nested/directory/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + ] + ); + } +} diff --git a/oxide/crates/node/Cargo.toml b/oxide/crates/node/Cargo.toml index 54995fa9e..0ded64922 100644 --- a/oxide/crates/node/Cargo.toml +++ b/oxide/crates/node/Cargo.toml @@ -8,8 +8,8 @@ crate-type = ["cdylib"] [dependencies] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -napi = { version = "2.10.0", default-features = false, features = ["napi4"] } -napi-derive = "2.11.1" +napi = { version = "2.13.1", default-features = false, features = ["napi4"] } +napi-derive = "2.13.0" tailwindcss-core = { path = "../core" } rayon = "1.5.3" diff --git a/oxide/crates/node/package.json b/oxide/crates/node/package.json index f9841b69f..72589305f 100644 --- a/oxide/crates/node/package.json +++ b/oxide/crates/node/package.json @@ -19,7 +19,7 @@ }, "license": "MIT", "devDependencies": { - "@napi-rs/cli": "^2.15.2" + "@napi-rs/cli": "^2.16.1" }, "engines": { "node": ">= 10" diff --git a/oxide/crates/node/src/lib.rs b/oxide/crates/node/src/lib.rs index 20961adcb..f974de1d5 100644 --- a/oxide/crates/node/src/lib.rs +++ b/oxide/crates/node/src/lib.rs @@ -1,3 +1,4 @@ +use napi::bindgen_prelude::{FromNapiValue, ToNapiValue}; use std::path::PathBuf; #[macro_use] @@ -11,16 +12,42 @@ pub struct ChangedContent { pub extension: String, } -#[napi] -pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { - tailwindcss_core::parse_candidate_strings_from_files( - changed_content - .into_iter() - .map(|changed_content| tailwindcss_core::ChangedContent { - file: changed_content.file.map(PathBuf::from), - content: changed_content.content, - extension: changed_content.extension, - }) - .collect(), - ) +impl From for tailwindcss_core::ChangedContent { + fn from(changed_content: ChangedContent) -> Self { + tailwindcss_core::ChangedContent { + file: changed_content.file.map(PathBuf::from), + content: changed_content.content, + extension: changed_content.extension, + } + } +} + +#[derive(Debug, Clone)] +#[napi(object)] +pub struct ContentPathInfo { + pub base: String, +} + +#[napi] +pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { + tailwindcss_core::resolve_content_paths(tailwindcss_core::ContentPathInfo { base: args.base }) +} + +#[derive(Debug)] +#[napi] +pub enum IO { + Sequential = 0b0001, + Parallel = 0b0010, +} + +#[derive(Debug)] +#[napi] +pub enum Parsing { + Sequential = 0b0100, + Parallel = 0b1000, +} + +#[napi] +pub fn parse_candidate_strings(input: Vec, strategy: u8) -> Vec { + tailwindcss_core::parse_candidate_strings(input.into_iter().map(Into::into).collect(), strategy) } diff --git a/package-lock.json b/package-lock.json index ecdc2141e..8d0a4f06c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@alloc/quick-lru": "^5.2.0", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", @@ -24,20 +24,20 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", + "resolve": "^1.22.3", "sucrase": "^3.32.0" }, "bin": { @@ -46,14 +46,11 @@ }, "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", @@ -71,7 +68,7 @@ "name": "@tailwindcss/integrations-content-resolution", "version": "0.0.0", "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -79,14 +76,14 @@ "name": "@tailwindcss/integrations-parcel", "version": "0.0.0", "devDependencies": { - "parcel": "^2.8.3" + "parcel": "^2.9.1" } }, "integrations/postcss-cli": { "name": "@tailwindcss/integrations-postcss-cli", "version": "0.0.0", "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -94,7 +91,7 @@ "name": "@tailwindcss/integrations-rollup", "version": "0.0.0", "devDependencies": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, @@ -102,9 +99,9 @@ "name": "@tailwindcss/integrations-rollup-sass", "version": "0.0.0", "devDependencies": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "^1.63.4" } }, "integrations/tailwindcss-cli": { @@ -119,7 +116,7 @@ "version": "0.0.0", "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.9" } }, "integrations/webpack-4": { @@ -1617,14 +1614,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1673,18 +1670,19 @@ } }, "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -1708,8 +1706,9 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -2311,9 +2310,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "cpu": [ "arm64" ], @@ -2324,9 +2323,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "cpu": [ "x64" ], @@ -2337,9 +2336,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "cpu": [ "arm" ], @@ -2350,9 +2349,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "cpu": [ "arm64" ], @@ -2363,9 +2362,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "cpu": [ "x64" ], @@ -2376,9 +2375,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "cpu": [ "x64" ], @@ -2422,9 +2421,9 @@ } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "cpu": [ "arm64" ], @@ -2435,9 +2434,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "cpu": [ "x64" ], @@ -2448,9 +2447,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "cpu": [ "arm" ], @@ -2461,9 +2460,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "cpu": [ "arm64" ], @@ -2474,9 +2473,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "cpu": [ "x64" ], @@ -2487,9 +2486,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "cpu": [ "x64" ], @@ -2500,9 +2499,9 @@ ] }, "node_modules/@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true, "bin": { "napi": "scripts/index.js" @@ -2545,21 +2544,21 @@ } }, "node_modules/@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2567,15 +2566,15 @@ } }, "node_modules/@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "dependencies": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" }, "engines": { "node": ">= 12.0.0" @@ -2585,13 +2584,13 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "dependencies": { "chalk": "^4.1.0" @@ -2605,16 +2604,16 @@ } }, "node_modules/@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2622,70 +2621,71 @@ } }, "node_modules/@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "dependencies": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -2715,9 +2715,9 @@ } }, "node_modules/@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", @@ -2732,9 +2732,9 @@ } }, "node_modules/@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -2745,16 +2745,16 @@ } }, "node_modules/@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "dependencies": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" }, "engines": { "node": ">= 12.0.0" @@ -2764,17 +2764,14 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", "dev": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, "engines": { "node": ">= 12.0.0" }, @@ -2784,9 +2781,9 @@ } }, "node_modules/@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "dependencies": { "nullthrows": "^1.1.1" @@ -2800,12 +2797,11 @@ } }, "node_modules/@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "dependencies": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" }, "engines": { @@ -2817,13 +2813,13 @@ } }, "node_modules/@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" }, "engines": { "node": ">= 12.0.0" @@ -2834,9 +2830,9 @@ } }, "node_modules/@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "dependencies": { "chalk": "^4.1.0" @@ -2850,18 +2846,18 @@ } }, "node_modules/@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2869,13 +2865,15 @@ } }, "node_modules/@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -2897,22 +2895,22 @@ } }, "node_modules/@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2920,12 +2918,12 @@ } }, "node_modules/@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -2933,7 +2931,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3009,20 +3007,19 @@ } }, "node_modules/@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3030,19 +3027,19 @@ } }, "node_modules/@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3117,22 +3114,22 @@ "node": ">=10.13.0" } }, - "node_modules/@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "node_modules/@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3140,17 +3137,18 @@ } }, "node_modules/@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "engines": { @@ -3161,7 +3159,7 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/package-manager/node_modules/semver": { @@ -3174,19 +3172,20 @@ } }, "node_modules/@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3194,20 +3193,20 @@ } }, "node_modules/@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3215,22 +3214,22 @@ } }, "node_modules/@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3238,9 +3237,9 @@ } }, "node_modules/@parcel/packager-js/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3253,16 +3252,16 @@ } }, "node_modules/@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3270,19 +3269,19 @@ } }, "node_modules/@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3290,12 +3289,30 @@ } }, "node_modules/@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "dependencies": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "dependencies": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" }, "engines": { "node": ">= 12.0.0" @@ -3306,20 +3323,20 @@ } }, "node_modules/@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3327,17 +3344,37 @@ } }, "node_modules/@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "dependencies": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3345,17 +3382,17 @@ } }, "node_modules/@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "dependencies": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3363,17 +3400,17 @@ } }, "node_modules/@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3381,18 +3418,19 @@ } }, "node_modules/@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3400,19 +3438,19 @@ } }, "node_modules/@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3420,18 +3458,18 @@ } }, "node_modules/@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3451,15 +3489,15 @@ } }, "node_modules/@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -3467,7 +3505,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3484,22 +3522,22 @@ } }, "node_modules/@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3507,14 +3545,14 @@ } }, "node_modules/@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3524,7 +3562,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3541,61 +3579,51 @@ } }, "node_modules/@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" - } - }, - "node_modules/@parcel/transformer-js/node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "dependencies": { - "tslib": "^2.4.0" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/transformer-js/node_modules/semver": { @@ -3608,17 +3636,17 @@ } }, "node_modules/@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3626,15 +3654,15 @@ } }, "node_modules/@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -3642,7 +3670,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3659,13 +3687,13 @@ } }, "node_modules/@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3674,7 +3702,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3691,16 +3719,16 @@ } }, "node_modules/@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3708,18 +3736,18 @@ } }, "node_modules/@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3727,14 +3755,14 @@ } }, "node_modules/@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3743,7 +3771,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3760,33 +3788,34 @@ } }, "node_modules/@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "dependencies": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "node_modules/@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "dependencies": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0" @@ -3817,16 +3846,16 @@ } }, "node_modules/@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { @@ -3837,7 +3866,7 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@pkgjs/parseargs": { @@ -3940,9 +3969,9 @@ } }, "node_modules/@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "hasInstallScript": true, "engines": { @@ -3953,16 +3982,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -3974,9 +4003,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "cpu": [ "arm64" ], @@ -3990,9 +4019,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "cpu": [ "x64" ], @@ -4006,9 +4035,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "cpu": [ "arm" ], @@ -4022,9 +4051,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "cpu": [ "arm64" ], @@ -4038,9 +4067,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "cpu": [ "arm64" ], @@ -4054,9 +4083,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "cpu": [ "x64" ], @@ -4070,9 +4099,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "cpu": [ "x64" ], @@ -4086,9 +4115,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "cpu": [ "arm64" ], @@ -4102,9 +4131,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "cpu": [ "ia32" ], @@ -4118,9 +4147,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "cpu": [ "x64" ], @@ -4138,8 +4167,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -5072,39 +5099,6 @@ "node": ">= 4.5.0" } }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -5644,9 +5638,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "funding": [ { "type": "opencollective", @@ -5655,13 +5649,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -5851,9 +5849,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==", + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==", "funding": [ { "type": "opencollective", @@ -5862,6 +5860,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -6585,6 +6587,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -6601,6 +6605,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -6615,6 +6621,8 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -6626,14 +6634,16 @@ } }, "node_modules/css-select/node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -6644,6 +6654,8 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.12" }, @@ -6656,6 +6668,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -6686,86 +6700,13 @@ "node": ">=4" } }, - "node_modules/cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "dependencies": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "css-tree": "~2.2.0" }, @@ -6779,6 +6720,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -6792,7 +6735,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/cyclist": { "version": "1.0.1", @@ -7014,8 +6959,9 @@ }, "node_modules/dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, - "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -7025,6 +6971,15 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -7037,19 +6992,21 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ], - "license": "BSD-2-Clause" + ] }, "node_modules/domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -7062,8 +7019,9 @@ }, "node_modules/domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -7101,9 +7059,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -7175,9 +7133,13 @@ } }, "node_modules/entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true, - "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -7276,16 +7238,16 @@ } }, "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -7295,8 +7257,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -7304,13 +7266,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -7381,9 +7342,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7466,14 +7427,14 @@ } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -8251,18 +8212,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fraction.js": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -8520,10 +8469,11 @@ "dev": true, "license": "ISC" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, - "license": "MIT" + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "node_modules/has": { "version": "1.0.3", @@ -8760,18 +8710,6 @@ "entities": "^3.0.1" } }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -10274,11 +10212,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/js-tokens": { "version": "4.0.0", "dev": true, @@ -10442,9 +10375,9 @@ } }, "node_modules/lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "dependencies": { "detect-libc": "^1.0.3" }, @@ -10456,20 +10389,20 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "cpu": [ "arm64" ], @@ -10486,9 +10419,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "cpu": [ "x64" ], @@ -10505,9 +10438,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "cpu": [ "arm" ], @@ -10524,9 +10457,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "cpu": [ "arm64" ], @@ -10543,9 +10476,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "cpu": [ "arm64" ], @@ -10562,9 +10495,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "cpu": [ "x64" ], @@ -10581,9 +10514,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "cpu": [ "x64" ], @@ -10600,9 +10533,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "cpu": [ "x64" ], @@ -10631,25 +10564,37 @@ "license": "MIT" }, "node_modules/lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "hasInstallScript": true, "dependencies": { - "msgpackr": "^1.5.4", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2" + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11" + } + }, + "node_modules/lmdb/node_modules/msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.1" } }, "node_modules/lmdb/node_modules/node-addon-api": { @@ -10812,7 +10757,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/memory-fs": { "version": "0.4.1", @@ -11104,34 +11051,46 @@ "license": "MIT" }, "node_modules/msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "optionalDependencies": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "node_modules/msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { - "node-gyp-build-optional-packages": "5.0.3" + "node-gyp-build-optional-packages": "5.0.7" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" } }, "node_modules/mz": { @@ -11239,9 +11198,9 @@ } }, "node_modules/node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true, "bin": { "node-gyp-build-optional-packages": "bin.js", @@ -11304,9 +11263,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -11315,14 +11274,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "6.1.0", "dev": true, @@ -11678,25 +11629,25 @@ } }, "node_modules/parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "dependencies": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" }, "bin": { "parcel": "lib/bin.js" @@ -11912,9 +11863,9 @@ } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "funding": [ { "type": "opencollective", @@ -11992,88 +11943,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -12201,104 +12070,6 @@ "node": ">=10" } }, - "node_modules/postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -12395,186 +12166,6 @@ "postcss": "^8.2.14" } }, - "node_modules/postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "dependencies": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -12596,8 +12187,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "license": "MIT", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -12606,37 +12198,6 @@ "node": ">=4" } }, - "node_modules/postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - }, - "engines": { - "node": "^14 || ^16 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-value-parser": { "version": "4.2.0", "license": "MIT" @@ -13102,11 +12663,11 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -13262,9 +12823,9 @@ } }, "node_modules/rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -13972,9 +13533,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -14763,22 +14324,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "node_modules/stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -14847,6 +14392,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -15494,7 +15041,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "funding": [ { "type": "opencollective", @@ -15503,15 +15052,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -15585,12 +15137,6 @@ "node": ">= 4" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -15619,13 +15165,13 @@ "dev": true }, "node_modules/vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "dependencies": { "esbuild": "^0.17.5", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" }, "bin": { @@ -16455,7 +16001,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "@napi-rs/cli": "^2.15.2" + "@napi-rs/cli": "^2.16.1" }, "engines": { "node": ">= 10" @@ -17121,14 +16667,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -17164,13 +16710,15 @@ } }, "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -17184,6 +16732,8 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -17696,44 +17246,44 @@ } }, "@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "dev": true, "optional": true }, "@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "dev": true, "optional": true }, "@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "dev": true, "optional": true }, @@ -17765,51 +17315,51 @@ } }, "@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "dev": true, "optional": true }, "@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true }, "@nodelib/fs.scandir": { @@ -17830,107 +17380,108 @@ } }, "@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "requires": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" } }, "@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "requires": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" } }, "@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -17952,9 +17503,9 @@ } }, "@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", @@ -17962,90 +17513,88 @@ } }, "@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true }, "@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "requires": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" } }, "@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3" - } + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", + "dev": true }, "@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "requires": { "nullthrows": "^1.1.1" } }, "@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "requires": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" } }, "@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" } }, "@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -18059,27 +17608,27 @@ } }, "@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -18142,27 +17691,26 @@ } }, "@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" } }, "@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "dependencies": { @@ -18221,32 +17769,33 @@ } } }, - "@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" } }, "@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "dependencies": { @@ -18259,49 +17808,50 @@ } }, "@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" } }, "@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "dependencies": { "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -18310,109 +17860,133 @@ } }, "@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" } }, "@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "requires": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + } + }, + "@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" } }, "@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" } }, "@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" + } + }, + "@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" } }, "@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "requires": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" } }, "@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" } }, "@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" } }, "@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -18426,15 +18000,15 @@ } }, "@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -18450,29 +18024,29 @@ } }, "@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18490,45 +18064,35 @@ } }, "@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "dependencies": { - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "requires": { - "tslib": "^2.4.0" - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -18538,25 +18102,25 @@ } }, "@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" } }, "@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -18572,13 +18136,13 @@ } }, "@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18595,34 +18159,34 @@ } }, "@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" } }, "@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18639,33 +18203,34 @@ } }, "@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "requires": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "requires": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" } }, "@parcel/watcher": { @@ -18681,16 +18246,16 @@ } }, "@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -18759,90 +18324,90 @@ } }, "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" } }, "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "dev": true, "optional": true }, @@ -18851,8 +18416,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "requires": { "tslib": "^2.4.0" } @@ -18890,36 +18453,36 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "^2.8.3" + "parcel": "^2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "^1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -18932,7 +18495,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.9" } }, "@tailwindcss/integrations-webpack-4": { @@ -19236,7 +18799,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "^2.15.2", + "@napi-rs/cli": "^2.16.1", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", @@ -19987,20 +19550,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, "babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -20428,14 +19977,14 @@ } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "bser": { @@ -20593,9 +20142,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==" + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==" }, "chalk": { "version": "4.1.2", @@ -21137,6 +20686,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -21150,6 +20701,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -21161,26 +20714,32 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0" } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "optional": true, + "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -21189,6 +20748,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -21203,65 +20764,13 @@ "cssesc": { "version": "3.0.0" }, - "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "requires": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "requires": {} - }, "csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-tree": "~2.2.0" }, @@ -21271,6 +20780,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -21280,7 +20791,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -21439,11 +20952,21 @@ }, "dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } } }, "domain-browser": { @@ -21454,10 +20977,14 @@ }, "domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -21465,6 +20992,8 @@ }, "domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -21497,9 +21026,9 @@ } }, "electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "elliptic": { "version": "6.5.4", @@ -21560,7 +21089,9 @@ } }, "entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true }, "envinfo": { @@ -21629,16 +21160,16 @@ "dev": true }, "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -21648,8 +21179,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -21657,13 +21188,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -21743,20 +21273,20 @@ } }, "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true }, "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -22339,10 +21869,6 @@ } } }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -22525,8 +22051,10 @@ "version": "4.2.10", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "has": { @@ -22680,14 +22208,6 @@ "domhandler": "^4.2.2", "domutils": "^2.8.0", "entities": "^3.0.1" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } } }, "http-cache-semantics": { @@ -23887,10 +23407,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, "js-tokens": { "version": "4.0.0", "dev": true @@ -24010,67 +23526,67 @@ } }, "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "requires": { "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "optional": true }, "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "optional": true }, "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "optional": true }, "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "optional": true }, "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "optional": true }, "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "optional": true }, "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "optional": true }, "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "optional": true }, "lilconfig": { @@ -24082,24 +23598,33 @@ "version": "1.2.4" }, "lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "requires": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2", - "msgpackr": "^1.5.4", + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, "dependencies": { + "msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "requires": { + "msgpackr-extract": "^3.0.1" + } + }, "node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -24230,7 +23755,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "memory-fs": { "version": "0.4.1", @@ -24451,28 +23978,37 @@ "dev": true }, "msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "requires": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "optional": true, "requires": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0", - "node-gyp-build-optional-packages": "5.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2", + "node-gyp-build-optional-packages": "5.0.7" + }, + "dependencies": { + "node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true + } } }, "mz": { @@ -24548,9 +24084,9 @@ "dev": true }, "node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true }, "node-int64": { @@ -24610,17 +24146,13 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "normalize-path": { "version": "3.0.0" }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, "normalize-url": { "version": "6.1.0", "dev": true @@ -24878,25 +24410,25 @@ } }, "parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "requires": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" } }, "parent-module": { @@ -25033,9 +24565,9 @@ "dev": true }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -25080,56 +24612,6 @@ } } }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "requires": {} - }, "postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -25199,68 +24681,6 @@ } } }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -25321,115 +24741,6 @@ "postcss-selector-parser": "^6.0.11" } }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, "postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -25441,31 +24752,14 @@ } }, "postcss-selector-parser": { - "version": "6.0.11", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-value-parser": { "version": "4.2.0" }, @@ -25811,11 +25105,11 @@ "dev": true }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -25920,9 +25214,9 @@ } }, "rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -26385,9 +25679,9 @@ "dev": true }, "sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -27002,16 +26296,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, "sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -27058,6 +26342,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -27072,7 +26358,7 @@ "requires": { "@alloc/quick-lru": "^5.2.0", "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "@tailwindcss/integrations-content-resolution": "file:integrations/content-resolution", @@ -27086,15 +26372,12 @@ "@tailwindcss/integrations-webpack-5": "file:integrations/webpack-5", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "autoprefixer": "^10.4.14", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "fast-glob": "^3.2.12", @@ -27103,21 +26386,21 @@ "jest": "^29.5.0", "jest-diff": "^29.5.0", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", "prettier": "^2.8.8", - "resolve": "^1.22.2", + "resolve": "^1.22.3", "rimraf": "^5.0.0", "source-map-js": "^1.0.2", "sucrase": "^3.32.0", @@ -27771,14 +27054,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -27814,13 +27097,15 @@ } }, "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -27834,6 +27119,8 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -28346,44 +27633,44 @@ } }, "@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "dev": true, "optional": true }, "@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "dev": true, "optional": true }, "@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "dev": true, "optional": true }, @@ -28415,51 +27702,51 @@ } }, "@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "dev": true, "optional": true }, "@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true }, "@nodelib/fs.scandir": { @@ -28480,107 +27767,108 @@ } }, "@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "requires": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" } }, "@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "requires": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" } }, "@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -28602,9 +27890,9 @@ } }, "@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", @@ -28612,90 +27900,88 @@ } }, "@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true }, "@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "requires": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" } }, "@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3" - } + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", + "dev": true }, "@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "requires": { "nullthrows": "^1.1.1" } }, "@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "requires": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" } }, "@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" } }, "@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -28709,27 +27995,27 @@ } }, "@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -28792,27 +28078,26 @@ } }, "@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" } }, "@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "dependencies": { @@ -28871,32 +28156,33 @@ } } }, - "@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" } }, "@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "dependencies": { @@ -28909,49 +28195,50 @@ } }, "@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" } }, "@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "dependencies": { "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -28960,109 +28247,133 @@ } }, "@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" } }, "@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "requires": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + } + }, + "@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" } }, "@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" } }, "@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" + } + }, + "@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" } }, "@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "requires": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" } }, "@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" } }, "@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" } }, "@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -29076,15 +28387,15 @@ } }, "@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -29100,29 +28411,29 @@ } }, "@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29140,45 +28451,35 @@ } }, "@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "dependencies": { - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "requires": { - "tslib": "^2.4.0" - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -29188,25 +28489,25 @@ } }, "@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" } }, "@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -29222,13 +28523,13 @@ } }, "@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29245,34 +28546,34 @@ } }, "@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" } }, "@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29289,33 +28590,34 @@ } }, "@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "requires": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "requires": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" } }, "@parcel/watcher": { @@ -29331,16 +28633,16 @@ } }, "@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -29409,90 +28711,90 @@ } }, "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" } }, "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "dev": true, "optional": true }, @@ -29501,8 +28803,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "requires": { "tslib": "^2.4.0" } @@ -29540,36 +28840,36 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "^2.8.3" + "parcel": "^2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.21.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "^1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -29582,7 +28882,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.9" } }, "@tailwindcss/integrations-webpack-4": { @@ -29886,7 +29186,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "^2.15.2", + "@napi-rs/cli": "^2.16.1", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", @@ -30637,20 +29937,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, "babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -31078,14 +30364,14 @@ } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "bser": { @@ -31243,9 +30529,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==" + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==" }, "chalk": { "version": "4.1.2", @@ -31787,6 +31073,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -31800,6 +31088,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -31811,26 +31101,32 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0" } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "optional": true, + "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -31839,6 +31135,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -31853,65 +31151,13 @@ "cssesc": { "version": "3.0.0" }, - "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "requires": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "requires": {} - }, "csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-tree": "~2.2.0" }, @@ -31921,6 +31167,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -31930,7 +31178,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -32089,11 +31339,21 @@ }, "dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } } }, "domain-browser": { @@ -32104,10 +31364,14 @@ }, "domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -32115,6 +31379,8 @@ }, "domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -32147,9 +31413,9 @@ } }, "electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "elliptic": { "version": "6.5.4", @@ -32210,7 +31476,9 @@ } }, "entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true }, "envinfo": { @@ -32279,16 +31547,16 @@ "dev": true }, "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -32298,8 +31566,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -32307,13 +31575,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -32393,20 +31660,20 @@ } }, "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true }, "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -32989,10 +32256,6 @@ } } }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -33175,8 +32438,10 @@ "version": "4.2.10", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "has": { @@ -33330,14 +32595,6 @@ "domhandler": "^4.2.2", "domutils": "^2.8.0", "entities": "^3.0.1" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } } }, "http-cache-semantics": { @@ -34537,10 +33794,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, "js-tokens": { "version": "4.0.0", "dev": true @@ -34660,67 +33913,67 @@ } }, "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "requires": { "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "optional": true }, "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "optional": true }, "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "optional": true }, "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "optional": true }, "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "optional": true }, "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "optional": true }, "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "optional": true }, "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "optional": true }, "lilconfig": { @@ -34732,24 +33985,33 @@ "version": "1.2.4" }, "lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "requires": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2", - "msgpackr": "^1.5.4", + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, "dependencies": { + "msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "requires": { + "msgpackr-extract": "^3.0.1" + } + }, "node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -34880,7 +34142,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "memory-fs": { "version": "0.4.1", @@ -35101,28 +34365,37 @@ "dev": true }, "msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "requires": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "optional": true, "requires": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0", - "node-gyp-build-optional-packages": "5.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2", + "node-gyp-build-optional-packages": "5.0.7" + }, + "dependencies": { + "node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true + } } }, "mz": { @@ -35198,9 +34471,9 @@ "dev": true }, "node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true }, "node-int64": { @@ -35260,17 +34533,13 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "normalize-path": { "version": "3.0.0" }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, "normalize-url": { "version": "6.1.0", "dev": true @@ -35528,25 +34797,25 @@ } }, "parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "requires": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" } }, "parent-module": { @@ -35683,9 +34952,9 @@ "dev": true }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -35730,56 +34999,6 @@ } } }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "requires": {} - }, "postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -35849,68 +35068,6 @@ } } }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -35971,115 +35128,6 @@ "postcss-selector-parser": "^6.0.11" } }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, "postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -36091,31 +35139,14 @@ } }, "postcss-selector-parser": { - "version": "6.0.11", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-value-parser": { "version": "4.2.0" }, @@ -36461,11 +35492,11 @@ "dev": true }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -36570,9 +35601,9 @@ } }, "rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -37035,9 +36066,9 @@ "dev": true }, "sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -37652,16 +36683,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, "sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -37708,6 +36729,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -38180,7 +37203,9 @@ "optional": true }, "update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -38249,12 +37274,6 @@ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -38282,14 +37301,14 @@ } }, "vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "requires": { "esbuild": "^0.17.5", "fsevents": "~2.3.2", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" } }, @@ -39376,7 +38395,9 @@ "optional": true }, "update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -39445,12 +38466,6 @@ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -39478,14 +38493,14 @@ } }, "vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "requires": { "esbuild": "^0.17.5", "fsevents": "~2.3.2", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" } }, diff --git a/package-lock.stable.json b/package-lock.stable.json deleted file mode 100644 index a80b9c55c..000000000 --- a/package-lock.stable.json +++ /dev/null @@ -1,13998 +0,0 @@ -{ - "name": "tailwindcss", - "version": "3.3.2", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "tailwindcss", - "version": "3.3.2", - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", - "@swc/jest": "^0.2.26", - "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", - "browserslist": "^4.21.5", - "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "jest": "^29.5.0", - "jest-diff": "^29.5.0", - "lightningcss": "1.18.0", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "source-map-js": "^1.0.2", - "turbo": "^1.9.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "integrations/content-resolution": { - "name": "@tailwindcss/integrations-content-resolution", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "postcss": "^8.4.21", - "postcss-cli": "^9.1.0" - } - }, - "integrations/parcel": { - "name": "@tailwindcss/integrations-parcel", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "parcel": "^2.5.0" - } - }, - "integrations/postcss-cli": { - "name": "@tailwindcss/integrations-postcss-cli", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "postcss": "^8.4.21", - "postcss-cli": "^9.1.0" - } - }, - "integrations/rollup": { - "name": "@tailwindcss/integrations-rollup", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "rollup": "^2.74.1", - "rollup-plugin-postcss": "^4.0.2" - } - }, - "integrations/rollup-sass": { - "name": "@tailwindcss/integrations-rollup-sass", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "rollup": "^2.74.1", - "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.51.0" - } - }, - "integrations/tailwindcss-cli": { - "name": "@tailwindcss/integrations-tailwindcss-cli", - "version": "0.0.0", - "extraneous": true, - "dependencies": { - "tailwindcss": "file:../../" - } - }, - "integrations/vite": { - "name": "@tailwindcss/integrations-vite", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "isomorphic-fetch": "^3.0.0", - "vite": "^2.9.9" - } - }, - "integrations/webpack-4": { - "name": "@tailwindcss/integrations-webpack-4", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "css-loader": "^5.2.7", - "mini-css-extract-plugin": "^1.6.2", - "postcss-loader": "^4.3.0", - "webpack": "^4.46.0", - "webpack-cli": "^4.9.2" - } - }, - "integrations/webpack-5": { - "name": "@tailwindcss/integrations-webpack-5", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "css-loader": "^6.7.1", - "mini-css-extract-plugin": "^2.7.2", - "postcss-loader": "^6.2.1", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.1" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz", - "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz", - "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz", - "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz", - "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz", - "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz", - "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz", - "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz", - "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz", - "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz", - "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz", - "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz", - "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz", - "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz", - "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz", - "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz", - "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz", - "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz", - "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz", - "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz", - "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz", - "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz", - "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/create-cache-key-function": { - "version": "27.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^27.4.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@mole-inc/bin-wrapper": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", - "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", - "dev": true, - "dependencies": { - "bin-check": "^4.1.0", - "bin-version-check": "^5.0.0", - "content-disposition": "^0.5.4", - "ext-name": "^5.0.0", - "file-type": "^17.1.6", - "filenamify": "^5.0.2", - "got": "^11.8.5", - "os-filter-obj": "^2.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0" - } - }, - "node_modules/@swc/cli": { - "version": "0.1.62", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", - "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==", - "dev": true, - "dependencies": { - "@mole-inc/bin-wrapper": "^8.0.1", - "commander": "^7.1.0", - "fast-glob": "^3.2.5", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "bin": { - "spack": "bin/spack.js", - "swc": "bin/swc.js", - "swcx": "bin/swcx.js" - }, - "engines": { - "node": ">= 12.13" - }, - "peerDependencies": { - "@swc/core": "^1.2.66", - "chokidar": "^3.5.1" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@swc/cli/node_modules/source-map": { - "version": "0.7.3", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", - "dev": true, - "hasInstallScript": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/jest": { - "version": "0.2.26", - "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.26.tgz", - "integrity": "sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==", - "dev": true, - "dependencies": { - "@jest/create-cache-key-function": "^27.4.2", - "jsonc-parser": "^3.2.0" - }, - "engines": { - "npm": ">= 7.0.0" - }, - "peerDependencies": { - "@swc/core": "*" - } - }, - "node_modules/@swc/register": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", - "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", - "dev": true, - "dependencies": { - "lodash.clonedeep": "^4.5.0", - "pirates": "^4.0.1", - "source-map-support": "^0.5.13" - }, - "bin": { - "swc-node": "bin/swc-node" - }, - "peerDependencies": { - "@swc/core": "^1.0.46" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "16.10.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/arg": { - "version": "5.0.2", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "dependencies": { - "execa": "^0.7.0", - "executable": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-version": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "find-versions": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version-check": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.0.0.tgz", - "integrity": "sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==", - "dev": true, - "dependencies": { - "bin-version": "^6.0.0", - "semver": "^7.3.5", - "semver-truncate": "^2.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/bin-version/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, - "node_modules/commander": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "license": "MIT" - }, - "node_modules/concurrently": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.0.1.tgz", - "integrity": "sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "date-fns": "^2.29.3", - "lodash": "^4.17.21", - "rxjs": "^7.8.0", - "shell-quote": "^1.8.0", - "spawn-command": "0.0.2-1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.1" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": "^14.13.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "dependencies": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - }, - "node_modules/date-fns": { - "version": "2.29.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "license": "Apache-2.0" - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", - "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.18", - "@esbuild/android-arm64": "0.17.18", - "@esbuild/android-x64": "0.17.18", - "@esbuild/darwin-arm64": "0.17.18", - "@esbuild/darwin-x64": "0.17.18", - "@esbuild/freebsd-arm64": "0.17.18", - "@esbuild/freebsd-x64": "0.17.18", - "@esbuild/linux-arm": "0.17.18", - "@esbuild/linux-arm64": "0.17.18", - "@esbuild/linux-ia32": "0.17.18", - "@esbuild/linux-loong64": "0.17.18", - "@esbuild/linux-mips64el": "0.17.18", - "@esbuild/linux-ppc64": "0.17.18", - "@esbuild/linux-riscv64": "0.17.18", - "@esbuild/linux-s390x": "0.17.18", - "@esbuild/linux-x64": "0.17.18", - "@esbuild/netbsd-x64": "0.17.18", - "@esbuild/openbsd-x64": "0.17.18", - "@esbuild/sunos-x64": "0.17.18", - "@esbuild/win32-arm64": "0.17.18", - "@esbuild/win32-ia32": "0.17.18", - "@esbuild/win32-x64": "0.17.18" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", - "dev": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/execa/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/execa/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "dependencies": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.11.0", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-type": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", - "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", - "dev": true, - "dependencies": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.9", - "token-types": "^5.0.0-alpha.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, - "node_modules/filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/filenamify": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", - "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", - "dev": true, - "dependencies": { - "filename-reserved-regex": "^3.0.0", - "strip-outer": "^2.0.0", - "trim-repeated": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", - "dev": true, - "dependencies": { - "semver-regex": "^4.0.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", - "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", - "dev": true, - "dependencies": { - "cliui": "^7.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jackspeak/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/levn/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/levn/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "license": "MIT", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "dependencies": { - "arch": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", - "dev": true, - "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.4", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "dependencies": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - }, - "engines": { - "node": "^14 || ^16 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "license": "MIT" - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/read-cache": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dev": true, - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", - "dev": true, - "dependencies": { - "glob": "^10.0.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semver-truncate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-2.0.0.tgz", - "integrity": "sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-truncate/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "dev": true, - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spawn-command": { - "version": "0.0.2-1", - "dev": true, - "license": "MIT" - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-outer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", - "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/trim-repeated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", - "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/trim-repeated/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true - }, - "node_modules/turbo": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.9.3.tgz", - "integrity": "sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "turbo": "bin/turbo" - }, - "optionalDependencies": { - "turbo-darwin-64": "1.9.3", - "turbo-darwin-arm64": "1.9.3", - "turbo-linux-64": "1.9.3", - "turbo-linux-arm64": "1.9.3", - "turbo-windows-64": "1.9.3", - "turbo-windows-arm64": "1.9.3" - } - }, - "node_modules/turbo-darwin-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.9.3.tgz", - "integrity": "sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-darwin-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.9.3.tgz", - "integrity": "sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-linux-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.9.3.tgz", - "integrity": "sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-linux-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.9.3.tgz", - "integrity": "sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-windows-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.9.3.tgz", - "integrity": "sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/turbo-windows-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.9.3.tgz", - "integrity": "sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "oxide": { - "name": "tailwindcss-oxide", - "version": "0.1.0", - "extraneous": true, - "license": "MIT", - "workspaces": [ - "node" - ] - }, - "oxide-node-api-shim": { - "name": "@tailwindcss/oxide-shim", - "extraneous": true, - "license": "MIT" - }, - "oxide/crates/node": { - "name": "@tailwindcss/oxide", - "version": "0.0.0", - "extraneous": true, - "license": "MIT", - "devDependencies": { - "@napi-rs/cli": "^2.14.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-darwin-arm64": "0.0.0", - "@tailwindcss/oxide-darwin-x64": "0.0.0", - "@tailwindcss/oxide-freebsd-x64": "0.0.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "0.0.0", - "@tailwindcss/oxide-linux-arm64-gnu": "0.0.0", - "@tailwindcss/oxide-linux-arm64-musl": "0.0.0", - "@tailwindcss/oxide-linux-x64-gnu": "0.0.0", - "@tailwindcss/oxide-linux-x64-musl": "0.0.0", - "@tailwindcss/oxide-win32-x64-msvc": "0.0.0" - } - } - }, - "dependencies": { - "@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", - "dev": true - }, - "@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@esbuild/android-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz", - "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz", - "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz", - "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz", - "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz", - "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz", - "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz", - "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz", - "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz", - "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz", - "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz", - "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz", - "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz", - "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz", - "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz", - "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz", - "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz", - "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz", - "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz", - "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz", - "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz", - "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz", - "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/create-cache-key-function": { - "version": "27.4.2", - "dev": true, - "requires": { - "@jest/types": "^27.4.2" - } - }, - "@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "requires": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - } - }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3" - } - }, - "@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/types": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - } - } - }, - "@mole-inc/bin-wrapper": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", - "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", - "dev": true, - "requires": { - "bin-check": "^4.1.0", - "bin-version-check": "^5.0.0", - "content-disposition": "^0.5.4", - "ext-name": "^5.0.0", - "file-type": "^17.1.6", - "filenamify": "^5.0.2", - "got": "^11.8.5", - "os-filter-obj": "^2.0.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true - }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0" - } - }, - "@swc/cli": { - "version": "0.1.62", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", - "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==", - "dev": true, - "requires": { - "@mole-inc/bin-wrapper": "^8.0.1", - "commander": "^7.1.0", - "fast-glob": "^3.2.5", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "dev": true - } - } - }, - "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", - "dev": true, - "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" - } - }, - "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", - "dev": true, - "optional": true - }, - "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", - "dev": true, - "optional": true - }, - "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", - "dev": true, - "optional": true - }, - "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", - "dev": true, - "optional": true - }, - "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", - "dev": true, - "optional": true - }, - "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", - "dev": true, - "optional": true - }, - "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", - "dev": true, - "optional": true - }, - "@swc/jest": { - "version": "0.2.26", - "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.26.tgz", - "integrity": "sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==", - "dev": true, - "requires": { - "@jest/create-cache-key-function": "^27.4.2", - "jsonc-parser": "^3.2.0" - } - }, - "@swc/register": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", - "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", - "dev": true, - "requires": { - "lodash.clonedeep": "^4.5.0", - "pirates": "^4.0.1", - "source-map-support": "^0.5.13" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true - }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "16.10.2", - "dev": true - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "16.0.4", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "dev": true - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "anymatch": { - "version": "3.1.2", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true - }, - "arg": { - "version": "5.0.2" - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "requires": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.0" - }, - "bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "executable": "^4.1.0" - } - }, - "bin-version": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "find-versions": "^5.0.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - } - } - }, - "bin-version-check": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.0.0.tgz", - "integrity": "sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==", - "dev": true, - "requires": { - "bin-version": "^6.0.0", - "semver": "^7.3.5", - "semver-truncate": "^2.0.0" - } - }, - "binary-extensions": { - "version": "2.2.0" - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "dev": true - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0" - }, - "to-regex-range": { - "version": "5.0.1", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "dev": true - }, - "colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, - "commander": { - "version": "7.2.0", - "dev": true - }, - "concat-map": { - "version": "0.0.1" - }, - "concurrently": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.0.1.tgz", - "integrity": "sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "date-fns": "^2.29.3", - "lodash": "^4.17.21", - "rxjs": "^7.8.0", - "shell-quote": "^1.8.0", - "spawn-command": "0.0.2-1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.1" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "dev": true, - "requires": {} - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "requires": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true - }, - "cssesc": { - "version": "3.0.0" - }, - "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "requires": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "requires": {} - }, - "csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "requires": { - "css-tree": "~2.2.0" - }, - "dependencies": { - "css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "requires": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - } - }, - "mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - } - } - }, - "date-fns": { - "version": "2.29.3", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "didyoumean": { - "version": "1.2.2" - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true - }, - "dlv": { - "version": "1.1.3" - }, - "doctrine": { - "version": "3.0.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, - "electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "esbuild": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", - "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.18", - "@esbuild/android-arm64": "0.17.18", - "@esbuild/android-x64": "0.17.18", - "@esbuild/darwin-arm64": "0.17.18", - "@esbuild/darwin-x64": "0.17.18", - "@esbuild/freebsd-arm64": "0.17.18", - "@esbuild/freebsd-x64": "0.17.18", - "@esbuild/linux-arm": "0.17.18", - "@esbuild/linux-arm64": "0.17.18", - "@esbuild/linux-ia32": "0.17.18", - "@esbuild/linux-loong64": "0.17.18", - "@esbuild/linux-mips64el": "0.17.18", - "@esbuild/linux-ppc64": "0.17.18", - "@esbuild/linux-riscv64": "0.17.18", - "@esbuild/linux-s390x": "0.17.18", - "@esbuild/linux-x64": "0.17.18", - "@esbuild/netbsd-x64": "0.17.18", - "@esbuild/openbsd-x64": "0.17.18", - "@esbuild/sunos-x64": "0.17.18", - "@esbuild/win32-arm64": "0.17.18", - "@esbuild/win32-ia32": "0.17.18", - "@esbuild/win32-x64": "0.17.18" - } - }, - "escalade": { - "version": "3.1.1", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-locate": { - "version": "5.0.0", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true - }, - "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "dev": true - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - } - } - }, - "executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "requires": { - "pify": "^2.2.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "dev": true - }, - "fastq": { - "version": "1.11.0", - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-type": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", - "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", - "dev": true, - "requires": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.9", - "token-types": "^5.0.0-alpha.2" - } - }, - "filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "dev": true - }, - "filenamify": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", - "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", - "dev": true, - "requires": { - "filename-reserved-regex": "^3.0.0", - "strip-outer": "^2.0.0", - "trim-repeated": "^2.0.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", - "dev": true, - "requires": { - "semver-regex": "^4.0.5" - } - }, - "flat-cache": { - "version": "3.0.4", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "3.1.1", - "dev": true - }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "dependencies": { - "signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", - "dev": true - } - } - }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0" - }, - "fsevents": { - "version": "2.3.2", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-path-inside": { - "version": "3.0.3", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jackspeak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", - "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", - "dev": true, - "requires": { - "@pkgjs/parseargs": "^0.11.0", - "cliui": "^7.0.4" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - } - } - }, - "jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - } - } - }, - "jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true - }, - "jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true - }, - "jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - } - }, - "jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" - }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "dev": true - }, - "keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "dependencies": { - "prelude-ls": { - "version": "1.2.1", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" - } - }, - "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", - "dev": true, - "optional": true - }, - "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", - "dev": true, - "optional": true - }, - "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", - "dev": true, - "optional": true - }, - "lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" - }, - "lines-and-columns": { - "version": "1.2.4" - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1" - }, - "micromatch": { - "version": "4.0.5", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0" - }, - "to-regex-range": { - "version": "5.0.1", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" - }, - "natural-compare": { - "version": "1.4.0", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0" - }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true - } - } - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1" - }, - "object-hash": { - "version": "3.0.0" - }, - "once": { - "version": "1.4.0", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "dependencies": { - "prelude-ls": { - "version": "1.2.1", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "requires": { - "arch": "^2.1.0" - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1" - }, - "path-key": { - "version": "3.1.1", - "dev": true - }, - "path-parse": { - "version": "1.0.7" - }, - "path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", - "dev": true, - "requires": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", - "dev": true - } - } - }, - "peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", - "dev": true - }, - "picocolors": { - "version": "1.0.0" - }, - "picomatch": { - "version": "2.3.1" - }, - "pify": { - "version": "2.3.0" - }, - "pirates": { - "version": "4.0.4" - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "requires": {} - }, - "postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "dependencies": { - "yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==" - } - } - }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "requires": { - "postcss-selector-parser": "^6.0.11" - } - }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-value-parser": { - "version": "4.2.0" - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3" - }, - "quick-lru": { - "version": "5.1.1", - "dev": true - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "read-cache": { - "version": "1.0.0", - "requires": { - "pify": "^2.3.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dev": true, - "requires": { - "readable-stream": "^3.6.0" - } - }, - "readdirp": { - "version": "3.6.0", - "requires": { - "picomatch": "^2.2.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true - }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "reusify": { - "version": "1.0.4" - }, - "rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", - "dev": true, - "requires": { - "glob": "^10.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - } - }, - "minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true - }, - "semver-truncate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-2.0.0.tgz", - "integrity": "sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "shebang-command": { - "version": "2.0.0", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "dev": true - }, - "shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "dev": true - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "dev": true, - "requires": { - "sort-keys": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "dev": true - }, - "source-map-js": { - "version": "1.0.2" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spawn-command": { - "version": "0.0.2-1", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": true - }, - "strip-outer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", - "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", - "dev": true - }, - "strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "dev": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - } - }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, - "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - } - } - }, - "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0" - }, - "svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dev": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "tree-kill": { - "version": "1.2.2", - "dev": true - }, - "trim-repeated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", - "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - } - } - }, - "ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true - }, - "turbo": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.9.3.tgz", - "integrity": "sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==", - "dev": true, - "requires": { - "turbo-darwin-64": "1.9.3", - "turbo-darwin-arm64": "1.9.3", - "turbo-linux-64": "1.9.3", - "turbo-linux-arm64": "1.9.3", - "turbo-windows-64": "1.9.3", - "turbo-windows-arm64": "1.9.3" - } - }, - "turbo-darwin-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.9.3.tgz", - "integrity": "sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==", - "dev": true, - "optional": true - }, - "turbo-darwin-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.9.3.tgz", - "integrity": "sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==", - "dev": true, - "optional": true - }, - "turbo-linux-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.9.3.tgz", - "integrity": "sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==", - "dev": true, - "optional": true - }, - "turbo-linux-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.9.3.tgz", - "integrity": "sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==", - "dev": true, - "optional": true - }, - "turbo-windows-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.9.3.tgz", - "integrity": "sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==", - "dev": true, - "optional": true - }, - "turbo-windows-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.9.3.tgz", - "integrity": "sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==", - "dev": true, - "optional": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2" - }, - "v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "which": { - "version": "2.0.2", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2" - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "dev": true - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "dev": true - } - } -} diff --git a/package.json b/package.json index e91533f0b..34db0a775 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tailwindcss", - "version": "3.3.2", + "version": "0.0.0-experimental.4", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "main": "lib/index.js", @@ -16,12 +16,9 @@ "integrations/*", "oxide/crates/node" ], - "tailwindcss": { - "engine": "oxide" - }, "scripts": { "dev": "concurrently -n tailwind,oxide-node -c green,yellow 'npm run dev:js' 'npm run dev:rust'", - "build": "npm run build:rust && npm run build:js && npm run build:peers", + "build": "npm run build:rust && npm run build:js", "test": "jest", "test:integrations": "npm run test -w ./integrations", "style": "eslint .", @@ -29,8 +26,7 @@ "dev:rust": "npm run --prefix ./oxide dev:node", "dev:js": "npm run build:js -- --watch", "build:rust": "npm run --prefix ./oxide build:node", - "build:js": "npm run generate:plugin-list && swc src --out-dir lib --copy-files --delete-dir-on-start --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"true\"'", - "build:peers": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "build:js": "npm run generate:plugin-list && swc src --out-dir lib --copy-files --delete-dir-on-start", "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", "generate:types": "node -r @swc/register scripts/generate-types.js" }, @@ -38,7 +34,6 @@ "src/*", "cli/*", "lib/*", - "peers/*", "scripts/*.js", "stubs/*", "nesting/*", @@ -49,14 +44,11 @@ ], "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", @@ -68,9 +60,9 @@ }, "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/oxide": "file:oxide/crates/node", + "@tailwindcss/oxide": "0.0.0-insiders.776d5bf", "arg": "^5.0.2", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", @@ -78,27 +70,25 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", + "resolve": "^1.22.3", "sucrase": "^3.32.0" }, "browserslist": [ - "> 1%", - "not edge <= 18", - "not ie 11", - "not op_mini all" + "defaults and supports css-variables and supports css-matches-pseudo", + "safari >= 14" ], "jest": { "testTimeout": 30000, diff --git a/package.stable.json b/package.stable.json deleted file mode 100644 index 308740509..000000000 --- a/package.stable.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "name": "tailwindcss", - "version": "3.3.2", - "description": "A utility-first CSS framework for rapidly building custom user interfaces.", - "license": "MIT", - "main": "lib/index.js", - "types": "types/index.d.ts", - "repository": "https://github.com/tailwindlabs/tailwindcss.git", - "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", - "homepage": "https://tailwindcss.com", - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "tailwindcss": { - "engine": "stable" - }, - "scripts": { - "prebuild": "npm run generate && rimraf lib", - "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", - "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", - "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", - "style": "eslint .", - "pretest": "npm run generate", - "test": "jest", - "test:integrations": "npm run test --prefix ./integrations", - "install:integrations": "node scripts/install-integrations.js", - "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", - "generate:types": "node -r @swc/register scripts/generate-types.js", - "generate": "npm run generate:plugin-list && npm run generate:types", - "release-channel": "node ./scripts/release-channel.js", - "release-notes": "node ./scripts/release-notes.js", - "prepublishOnly": "npm install --force && npm run build" - }, - "files": [ - "src/*", - "cli/*", - "lib/*", - "peers/*", - "scripts/*.js", - "stubs/*", - "nesting/*", - "types/**/*", - "*.d.ts", - "*.css", - "*.js" - ], - "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", - "@swc/jest": "^0.2.26", - "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", - "browserslist": "^4.21.5", - "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "jest": "^29.5.0", - "jest-diff": "^29.5.0", - "lightningcss": "1.18.0", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "source-map-js": "^1.0.2", - "turbo": "^1.9.3" - }, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "browserslist": [ - "> 1%", - "not edge <= 18", - "not ie 11", - "not op_mini all" - ], - "jest": { - "testTimeout": 30000, - "setupFilesAfterEnv": [ - "/jest/customMatchers.js" - ], - "testPathIgnorePatterns": [ - "/node_modules/", - "/integrations/", - "/standalone-cli/", - "\\.test\\.skip\\.js$" - ], - "transformIgnorePatterns": [ - "node_modules/(?!lightningcss)" - ], - "transform": { - "\\.js$": "@swc/jest", - "\\.ts$": "@swc/jest" - } - }, - "engines": { - "node": ">=14.0.0" - } -} diff --git a/scripts/swap-engines.js b/scripts/swap-engines.js deleted file mode 100644 index ef8308aeb..000000000 --- a/scripts/swap-engines.js +++ /dev/null @@ -1,40 +0,0 @@ -let fs = require('fs') -let path = require('path') - -let engines = { - stable: { - files: [ - path.resolve(__dirname, '..', 'package.stable.json'), - path.resolve(__dirname, '..', 'package-lock.stable.json'), - ], - }, - oxide: { - files: [ - path.resolve(__dirname, '..', 'package.oxide.json'), - path.resolve(__dirname, '..', 'package-lock.oxide.json'), - ], - }, -} - -// Find out what the current engine is that we are using: -let [otherEngine, info] = Object.entries(engines).find(([, info]) => - info.files.every((file) => fs.existsSync(file)) -) -let currentEngine = otherEngine === 'oxide' ? 'stable' : 'oxide' - -console.log(`Current engine: \`${currentEngine}\`, swapping to \`${otherEngine}\``) - -// Swap the engines -for (let file of info.files) { - fs.renameSync( - file.replace(`.${otherEngine}`, ''), - file.replace(`.${otherEngine}`, `.${currentEngine}`) - ) -} -for (let file of engines[otherEngine].files) { - fs.renameSync(file, file.replace(`.${otherEngine}`, '')) -} - -console.log( - 'Engines have been swapped. Make sure to run `npm install` to update your dependencies.' -) diff --git a/src/cli-peer-dependencies.js b/src/cli-peer-dependencies.js deleted file mode 100644 index 6b9f986aa..000000000 --- a/src/cli-peer-dependencies.js +++ /dev/null @@ -1,15 +0,0 @@ -export function lazyPostcss() { - return require('postcss') -} - -export function lazyPostcssImport() { - return require('postcss-import') -} - -export function lazyAutoprefixer() { - return require('autoprefixer') -} - -export function lazyCssnano() { - return require('cssnano') -} diff --git a/src/cli.js b/src/cli.js index 4b73accbb..9a5aff27b 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,7 +1,3 @@ #!/usr/bin/env node -if (__OXIDE__) { - module.exports = require('./oxide/cli') -} else { - module.exports = require('./cli/index') -} +module.exports = require('./cli/index') diff --git a/src/cli/build/deps.js b/src/cli/build/deps.js deleted file mode 100644 index 9435b929a..000000000 --- a/src/cli/build/deps.js +++ /dev/null @@ -1,56 +0,0 @@ -// @ts-check - -import { - // @ts-ignore - lazyPostcss, - - // @ts-ignore - lazyPostcssImport, - - // @ts-ignore - lazyCssnano, - - // @ts-ignore - lazyAutoprefixer, -} from '../../../peers/index.js' - -/** - * @returns {import('postcss')} - */ -export function loadPostcss() { - // Try to load a local `postcss` version first - try { - return require('postcss') - } catch {} - - return lazyPostcss() -} - -export function loadPostcssImport() { - // Try to load a local `postcss-import` version first - try { - return require('postcss-import') - } catch {} - - return lazyPostcssImport() -} - -export function loadCssNano() { - let options = { preset: ['default', { cssDeclarationSorter: false }] } - - // Try to load a local `cssnano` version first - try { - return require('cssnano') - } catch {} - - return lazyCssnano()(options) -} - -export function loadAutoprefixer() { - // Try to load a local `autoprefixer` version first - try { - return require('autoprefixer') - } catch {} - - return lazyAutoprefixer() -} diff --git a/src/cli/build/index.js b/src/cli/build/index.js index 62c020e59..a142a4a47 100644 --- a/src/cli/build/index.js +++ b/src/cli/build/index.js @@ -25,6 +25,10 @@ export async function build(args) { process.exit(9) } + if (args['--no-autoprefixer']) { + console.error('[deprecation] The --no-autoprefixer flag is deprecated and has no effect.') + } + // TODO: Reference the @config path here if exists let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath() diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index 9f3f6f52f..6b40f13c3 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -1,14 +1,17 @@ // @ts-check +import pkg from '../../../package.json' import path from 'path' import fs from 'fs' +import postcss from 'postcss' import postcssrc from 'postcss-load-config' +import browserslist from 'browserslist' +import lightning, { Features } from 'lightningcss' import { lilconfig } from 'lilconfig' import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API import tailwind from '../../processTailwindFeatures' -import { loadAutoprefixer, loadCssNano, loadPostcss, loadPostcssImport } from './deps' import { formatNodes, drainStdin, outputFile } from './utils' import { env } from '../../lib/sharedState' import resolveConfig from '../../../resolveConfig.js' @@ -19,6 +22,50 @@ import { findAtConfigPath } from '../../lib/findAtConfigPath.js' import log from '../../util/log' import { loadConfig } from '../../lib/load-config' import getModuleDependencies from '../../lib/getModuleDependencies' +import { validateConfig } from '../../util/validateConfig' +import { handleImportAtRules } from '../../lib/handleImportAtRules' +import { flagEnabled } from '../../featureFlags' +import { CssBasedConfig } from '../../lib/parseCssConfig.js' + +async function lightningcss(result, { map = true, minify = true } = {}) { + try { + let resolvedBrowsersListConfig = browserslist.findConfig( + result.opts.from ?? process.cwd() + )?.defaults + let defaultBrowsersListConfig = pkg.browserslist + let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig + + let transformed = lightning.transform({ + filename: result.opts.from || 'input.css', + code: Buffer.from(result.css, 'utf-8'), + minify, + sourceMap: result.map === undefined ? map : !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: lightning.browserslistToTargets(browserslist(browsersListConfig)), + drafts: { + nesting: true, + }, + include: Features.Nesting, + exclude: Features.LogicalProperties, + }) + + return Object.assign(result, { + css: transformed.code.toString('utf8'), + map: result.map + ? Object.assign(result.map, { + toString() { + return transformed.map?.toString() + }, + }) + : result.map, + }) + } catch (err) { + console.error('Unable to use Lightning CSS. Using raw version instead.') + console.error(err) + + return result + } +} /** * @@ -75,39 +122,6 @@ async function loadPostCssPlugins(customPostCssPath) { return [beforePlugins, afterPlugins, config.options] } -function loadBuiltinPostcssPlugins() { - let postcss = loadPostcss() - let IMPORT_COMMENT = '__TAILWIND_RESTORE_IMPORT__: ' - return [ - [ - (root) => { - root.walkAtRules('import', (rule) => { - if (rule.params.slice(1).startsWith('tailwindcss/')) { - rule.after(postcss.comment({ text: IMPORT_COMMENT + rule.params })) - rule.remove() - } - }) - }, - loadPostcssImport(), - (root) => { - root.walkComments((rule) => { - if (rule.text.startsWith(IMPORT_COMMENT)) { - rule.after( - postcss.atRule({ - name: 'import', - params: rule.text.replace(IMPORT_COMMENT, ''), - }) - ) - rule.remove() - } - }) - }, - ], - [], - {}, - ] -} - let state = { /** @type {any} */ context: null, @@ -118,7 +132,7 @@ let state = { /** @type {{content: string, extension: string}[]} */ changedContent: [], - /** @type {ReturnType | null} */ + /** @type {{config: import('../../../types').Config, dependencies: Set, dispose: Function } | null} */ configBag: null, contextDependencies: new Set(), @@ -143,7 +157,7 @@ let state = { } }, - loadConfig(configPath, content) { + loadConfig(configPath, content, cssThemeValues) { if (this.watcher && configPath) { this.refreshConfigDependencies() } @@ -160,8 +174,7 @@ let state = { }, } - // @ts-ignore - this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } }) + this.configBag.config = validateConfig(resolveConfig(this.configBag.config, { theme: cssThemeValues })) // Override content files if `--content` has been passed explicitly if (content?.length > 0) { @@ -185,7 +198,7 @@ let state = { let files = fastGlob.sync(this.contentPatterns.all) for (let file of files) { - if (__OXIDE__) { + if (flagEnabled(this.config, 'oxideParser')) { content.push({ file, extension: path.extname(file).slice(1), @@ -210,7 +223,7 @@ let state = { return content }, - getContext({ createContext, cliConfigPath, root, result, content }) { + getContext({ createContext, cliConfigPath, root, result, content, cssThemeValues }) { if (this.context) { this.context.changedContent = this.changedContent.splice(0) @@ -222,7 +235,7 @@ let state = { env.DEBUG && console.timeEnd('Searching for config') env.DEBUG && console.time('Loading config') - let config = this.loadConfig(configPath, content) + let config = this.loadConfig(configPath, content, cssThemeValues) env.DEBUG && console.timeEnd('Loading config') env.DEBUG && console.time('Creating context') @@ -251,8 +264,6 @@ let state = { } export async function createProcessor(args, cliConfigPath) { - let postcss = loadPostcss() - let input = args['--input'] let output = args['--output'] let includePostCss = args['--postcss'] @@ -260,7 +271,9 @@ export async function createProcessor(args, cliConfigPath) { let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) - : loadBuiltinPostcssPlugins() + : [[], [], {}] + + beforePlugins.unshift(...handleImportAtRules()) if (args['--purge']) { log.warn('purge-flag-deprecated', [ @@ -279,6 +292,9 @@ export async function createProcessor(args, cliConfigPath) { return { postcssPlugin: 'tailwindcss', Once(root, { result }) { + // Parse any CSS-based config values from `:theme` rules + let cssThemeValues = new CssBasedConfig().parse(root) + env.DEBUG && console.time('Compiling CSS') tailwind(({ createContext }) => { console.error() @@ -291,6 +307,7 @@ export async function createProcessor(args, cliConfigPath) { root, result, content, + cssThemeValues, }) } })(root, result) @@ -306,8 +323,6 @@ export async function createProcessor(args, cliConfigPath) { tailwindPlugin, !args['--minify'] && formatNodes, ...afterPlugins, - !args['--no-autoprefixer'] && loadAutoprefixer(), - args['--minify'] && loadCssNano(), ].filter(Boolean) /** @type {import('postcss').Processor} */ @@ -331,9 +346,20 @@ export async function createProcessor(args, cliConfigPath) { async function build() { let start = process.hrtime.bigint() + let options = { + ...postcssOptions, + from: input, + to: output, + } return readInput() - .then((css) => processor.process(css, { ...postcssOptions, from: input, to: output })) + .then((css) => processor.process(css, options)) + .then((result) => + lightningcss(result, { + ...options, + minify: !!args['--minify'], + }) + ) .then((result) => { if (!state.watcher) { return result diff --git a/src/cli/index.js b/src/cli/index.js index fc1497f62..66dda931c 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -70,6 +70,7 @@ let commands = { description: 'Path to a custom config file', }, '--no-autoprefixer': { + deprecated: true, type: Boolean, description: 'Disable autoprefixer', }, diff --git a/src/corePlugins.js b/src/corePlugins.js index e4d2ff279..00ceab259 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -386,6 +386,26 @@ export let variantPlugins = { ) }, + hasVariants: ({ matchVariant }) => { + matchVariant('has', (value) => `&:has(${normalize(value)})`, { values: {} }) + matchVariant( + 'group-has', + (value, { modifier }) => + modifier + ? `:merge(.group\\/${modifier}):has(${normalize(value)}) &` + : `:merge(.group):has(${normalize(value)}) &`, + { values: {} } + ) + matchVariant( + 'peer-has', + (value, { modifier }) => + modifier + ? `:merge(.peer\\/${modifier}):has(${normalize(value)}) ~ &` + : `:merge(.peer):has(${normalize(value)}) ~ &`, + { values: {} } + ) + }, + ariaVariants: ({ matchVariant, theme }) => { matchVariant('aria', (value) => `&[aria-${normalize(value)}]`, { values: theme('aria') ?? {} }) matchVariant( @@ -1255,13 +1275,13 @@ export let corePlugins = { ], ]), - space: ({ matchUtilities, addUtilities, theme }) => { + space: ({ matchUtilities, addUtilities, theme, config }) => { matchUtilities( { 'space-x': (value) => { value = value === '0' ? '0px' : value - if (__OXIDE__) { + if (flagEnabled(config(), 'logicalSiblingUtilities')) { return { '& > :not([hidden]) ~ :not([hidden])': { '--tw-space-x-reverse': '0', @@ -1300,13 +1320,13 @@ export let corePlugins = { }) }, - divideWidth: ({ matchUtilities, addUtilities, theme }) => { + divideWidth: ({ matchUtilities, addUtilities, theme, config }) => { matchUtilities( { 'divide-x': (value) => { value = value === '0' ? '0px' : value - if (__OXIDE__) { + if (flagEnabled(config(), 'logicalSiblingUtilities')) { return { '& > :not([hidden]) ~ :not([hidden])': { '@defaults border-width': {}, @@ -1503,6 +1523,14 @@ export let corePlugins = { }) }, + textWrap: ({ addUtilities }) => { + addUtilities({ + '.text-wrap': { 'text-wrap': 'wrap' }, + '.text-nowrap': { 'text-wrap': 'nowrap' }, + '.text-balance': { 'text-wrap': 'balance' }, + }) + }, + wordBreak: ({ addUtilities }) => { addUtilities({ '.break-normal': { 'overflow-wrap': 'normal', 'word-break': 'normal' }, diff --git a/src/css/preflight.css b/src/css/preflight.css index fab875d95..4935b607b 100644 --- a/src/css/preflight.css +++ b/src/css/preflight.css @@ -163,6 +163,8 @@ optgroup, select, textarea { font-family: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ font-size: 100%; /* 1 */ font-weight: inherit; /* 1 */ line-height: inherit; /* 1 */ @@ -264,7 +266,7 @@ summary { } /* -Removes the default spacing and border for appropriate elements. +Removes the default spacing for appropriate elements. */ blockquote, @@ -300,6 +302,10 @@ menu { padding: 0; } +dialog { + padding: 0; +} + /* Prevent resizing textareas horizontally by default. */ diff --git a/src/featureFlags.js b/src/featureFlags.js index dc9f2d7c4..c594bd969 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -3,25 +3,23 @@ import log from './util/log' let defaults = { optimizeUniversalDefaults: false, - generalizedModifiers: true, - get disableColorOpacityUtilitiesByDefault() { - return __OXIDE__ - }, - get relativeContentPathsByDefault() { - return __OXIDE__ - }, + disableColorOpacityUtilitiesByDefault: true, + relativeContentPathsByDefault: false, + oxideParser: true, + logicalSiblingUtilities: false, } -let featureFlags = { +export let featureFlags = { future: [ 'hoverOnlyWhenSupported', 'respectDefaultRingColorOpacity', 'disableColorOpacityUtilitiesByDefault', 'relativeContentPathsByDefault', + 'logicalSiblingUtilities', ], experimental: [ 'optimizeUniversalDefaults', - 'generalizedModifiers', + 'oxideParser', // 'variantGrouping', ], } diff --git a/src/lib/content.js b/src/lib/content.js index e814efe4d..9979d251d 100644 --- a/src/lib/content.js +++ b/src/lib/content.js @@ -7,10 +7,40 @@ import fastGlob from 'fast-glob' import normalizePath from 'normalize-path' import { parseGlob } from '../util/parseGlob' import { env } from './sharedState' +import { resolveContentPaths } from '@tailwindcss/oxide' /** @typedef {import('../../types/config.js').RawFile} RawFile */ /** @typedef {import('../../types/config.js').FilePath} FilePath */ +/* + * @param {import('tailwindcss').Config} tailwindConfig + * @param {{skip:string[]}} options + * @returns {ContentPath[]} + */ +function resolveContentFiles(tailwindConfig, { skip = [] } = {}) { + if ( + Array.isArray(tailwindConfig.content.files) && + tailwindConfig.content.files.includes('auto') + ) { + let idx = tailwindConfig.content.files.indexOf('auto') + if (idx !== -1) { + env.DEBUG && console.time('Calculating resolve content paths') + let resolved = resolveContentPaths({ base: process.cwd() }) + env.DEBUG && console.timeEnd('Calculating resolve content paths') + + tailwindConfig.content.files.splice(idx, 1, ...resolved) + } + } + + if (skip.length > 0) { + tailwindConfig.content.files = tailwindConfig.content.files.filter( + (filePath) => !skip.includes(filePath) + ) + } + + return tailwindConfig.content.files +} + /** * @typedef {object} ContentPath * @property {string} original @@ -32,7 +62,9 @@ import { env } from './sharedState' * @returns {ContentPath[]} */ export function parseCandidateFiles(context, tailwindConfig) { - let files = tailwindConfig.content.files + let files = resolveContentFiles(tailwindConfig, { + skip: [context.userConfigPath], + }) // Normalize the file globs files = files.filter((filePath) => typeof filePath === 'string') diff --git a/src/lib/evaluateTailwindFunctions.js b/src/lib/evaluateTailwindFunctions.js index 7e04ef428..ff73f466c 100644 --- a/src/lib/evaluateTailwindFunctions.js +++ b/src/lib/evaluateTailwindFunctions.js @@ -1,7 +1,7 @@ import dlv from 'dlv' import didYouMean from 'didyoumean' import transformThemeValue from '../util/transformThemeValue' -import parseValue from 'postcss-value-parser' +import parseValue from '../value-parser/index' import { normalizeScreens } from '../util/normalizeScreens' import buildMediaQuery from '../util/buildMediaQuery' import { toPath } from '../util/toPath' @@ -146,6 +146,9 @@ function resolveVNode(node, vNode, functions) { } function resolveFunctions(node, input, functions) { + let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`)) + if (!hasAnyFn) return input + return parseValue(input) .walk((vNode) => { resolveVNode(node, vNode, functions) diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index bf7d8f17f..5f4391a15 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -1,10 +1,12 @@ import fs from 'fs' import LRU from '@alloc/quick-lru' +import { parseCandidateStrings, IO, Parsing } from '@tailwindcss/oxide' import * as sharedState from './sharedState' import { generateRules } from './generateRules' import log from '../util/log' import cloneNodes from '../util/cloneNodes' import { defaultExtractor } from './defaultExtractor' +import { flagEnabled } from '../featureFlags' let env = sharedState.env @@ -24,7 +26,10 @@ function getExtractor(context, fileExtension) { extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || - builtInExtractors.DEFAULT(context) + // Because we call `DEFAULT(context)`, the returning function is always a new function without a + // stable identity. Marking it with `DEFAULT_EXTRACTOR` allows us to check if it is the default + // extractor without relying on the function identity. + Object.assign(builtInExtractors.DEFAULT(context), { DEFAULT_EXTRACTOR: true }) ) } @@ -130,20 +135,36 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Reading changed files') - if (__OXIDE__) { - // TODO: Pass through or implement `extractor` - for (let candidate of require('@tailwindcss/oxide').parseCandidateStringsFromFiles( - context.changedContent - // Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform) - )) { - candidates.add(candidate) + if (flagEnabled(context.tailwindConfig, 'oxideParser')) { + let rustParserContent = [] + let regexParserContent = [] + + for (let item of context.changedContent) { + let transformer = getTransformer(context.tailwindConfig, item.extension) + let extractor = getExtractor(context, item.extension) + + if (transformer === builtInTransformers.DEFAULT && extractor?.DEFAULT_EXTRACTOR === true) { + rustParserContent.push(item) + } else { + regexParserContent.push([item, { transformer, extractor }]) + } } - // for (let { file, content, extension } of context.changedContent) { - // let transformer = getTransformer(context.tailwindConfig, extension) - // let extractor = getExtractor(context, extension) - // getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen) - // } + if (rustParserContent.length > 0) { + for (let candidate of parseCandidateStrings( + rustParserContent, + IO.Parallel | Parsing.Parallel + )) { + candidates.add(candidate) + } + } + + if (regexParserContent.length > 0) { + for (let [{ file, content }, { transformer, extractor }] of regexParserContent) { + content = file ? fs.readFileSync(file, 'utf8') : content + getClassCandidates(transformer(content), extractor, candidates, seen) + } + } } else { for (let { file, content, extension } of context.changedContent) { let transformer = getTransformer(context.tailwindConfig, extension) @@ -162,15 +183,16 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Generate rules') env.DEBUG && console.time('Sorting candidates') - let sortedCandidates = __OXIDE__ - ? candidates - : new Set( - [...candidates].sort((a, z) => { - if (a === z) return 0 - if (a < z) return -1 - return 1 - }) - ) + // TODO: only sort if we are not using the oxide parser (flagEnabled(context.tailwindConfig, + // 'oxideParser')) AND if we got all the candidates form the oxideParser alone. This will not + // be the case currently if you have custom transformers / extractors. + let sortedCandidates = new Set( + [...candidates].sort((a, z) => { + if (a === z) return 0 + if (a < z) return -1 + return 1 + }) + ) env.DEBUG && console.timeEnd('Sorting candidates') generateRules(sortedCandidates, context) env.DEBUG && console.timeEnd('Generate rules') @@ -244,11 +266,21 @@ export default function expandTailwindAtRules(context) { ) layerNodes.variants.remove() } else if (variantNodes.length > 0) { - root.append( - cloneNodes(variantNodes, root.source, { - layer: 'variants', + let cloned = cloneNodes(variantNodes, undefined, { + layer: 'variants', + }) + + cloned.forEach((node) => { + let parentLayer = node.raws.tailwind?.parentLayer ?? null + + node.walk((n) => { + if (!n.source) { + n.source = layerNodes[parentLayer].source + } }) - ) + }) + + root.append(cloned) } // If we've got a utility layer and no utilities are generated there's likely something wrong diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 60da2323f..67344d370 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -45,7 +45,7 @@ function* candidatePermutations(candidate) { let bracketIdx = candidate.indexOf('[') // If character before `[` isn't a dash or a slash, this isn't a dynamic class - // eg. string[] + // e.g. string[] if (candidate[bracketIdx - 1] === '-') { dashIdx = bracketIdx - 1 } else if (candidate[bracketIdx - 1] === '/') { @@ -175,10 +175,6 @@ function applyVariant(variant, matches, context) { if (modifiers.length && !context.variantMap.has(variant)) { variant = baseVariant args.modifier = modifiers[0] - - if (!flagEnabled(context.tailwindConfig, 'generalizedModifiers')) { - return [] - } } } @@ -193,13 +189,13 @@ function applyVariant(variant, matches, context) { // group[:hover] (`-` is missing) let match = /(.)(-?)\[(.*)\]/g.exec(variant) if (match) { - let [, char, seperator, value] = match + let [, char, separator, value] = match // @-[200px] case - if (char === '@' && seperator === '-') return [] + if (char === '@' && separator === '-') return [] // group[:hover] case - if (char !== '@' && seperator === '') return [] + if (char !== '@' && separator === '') return [] - variant = variant.replace(`${seperator}[${value}]`, '') + variant = variant.replace(`${separator}[${value}]`, '') args.value = value } } @@ -459,9 +455,9 @@ function isParsableNode(node) { } function isParsableCssValue(property, value) { - // We don't want to to treat [https://example.com] as a custom property + // We don't want to treat [https://example.com] as a custom property // Even though, according to the CSS grammar, it's a totally valid CSS declaration - // So we short-circuit here by checking if the custom property looks like a url + // So we short-circuit here by checking if the custom property looks like a URL if (looksLikeUri(`${property}:${value}`)) { return false } diff --git a/src/lib/handleImportAtRules.js b/src/lib/handleImportAtRules.js new file mode 100644 index 000000000..bcb55b5db --- /dev/null +++ b/src/lib/handleImportAtRules.js @@ -0,0 +1,34 @@ +import postcss from 'postcss' +import postcssImport from 'postcss-import' + +const TAILWIND = Symbol() + +export function handleImportAtRules() { + let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__' + let atRulesToRestore = ['tailwind', 'config'] + + return [ + (root) => { + root.walkAtRules((rule) => { + if (!atRulesToRestore.includes(rule.name)) return rule + + rule.after( + postcss.comment({ + text: RESTORE_ATRULE_COMMENT, + raws: { [TAILWIND]: { rule } }, + }) + ) + rule.remove() + }) + }, + postcssImport(), + (root) => { + root.walkComments((rule) => { + if (rule.text === RESTORE_ATRULE_COMMENT) { + rule.after(rule.raws[TAILWIND].rule) + rule.remove() + } + }) + }, + ] +} diff --git a/src/lib/normalizeTailwindDirectives.js b/src/lib/normalizeTailwindDirectives.js index 3349a7e3a..0366d1662 100644 --- a/src/lib/normalizeTailwindDirectives.js +++ b/src/lib/normalizeTailwindDirectives.js @@ -10,33 +10,6 @@ export default function normalizeTailwindDirectives(root) { applyDirectives.add(atRule) } - if (atRule.name === 'import') { - if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { - atRule.name = 'tailwind' - atRule.params = 'base' - } else if ( - atRule.params === '"tailwindcss/components"' || - atRule.params === "'tailwindcss/components'" - ) { - atRule.name = 'tailwind' - atRule.params = 'components' - } else if ( - atRule.params === '"tailwindcss/utilities"' || - atRule.params === "'tailwindcss/utilities'" - ) { - atRule.name = 'tailwind' - atRule.params = 'utilities' - } else if ( - atRule.params === '"tailwindcss/screens"' || - atRule.params === "'tailwindcss/screens'" || - atRule.params === '"tailwindcss/variants"' || - atRule.params === "'tailwindcss/variants'" - ) { - atRule.name = 'tailwind' - atRule.params = 'variants' - } - } - if (atRule.name === 'tailwind') { if (atRule.params === 'screens') { atRule.params = 'variants' diff --git a/src/lib/offsets.js b/src/lib/offsets.js index a43ebe4f3..0ecc04b77 100644 --- a/src/lib/offsets.js +++ b/src/lib/offsets.js @@ -23,7 +23,7 @@ import { remapBitfield } from './remap-bitfield.js' * @property {bigint} arbitrary 0n if false, 1n if true * @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants * @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable. - * @property {bigint} index Index of the rule / utility in it's given *parent* layer. Monotonically increasing. + * @property {bigint} index Index of the rule / utility in its given *parent* layer. Monotonically increasing. * @property {VariantOption[]} options Some information on how we can sort arbitrary variants */ @@ -302,7 +302,7 @@ export class Offsets { let mapping = this.recalculateVariantOffsets() // No arbitrary variants? Nothing to do. - // Everyhing already in order? Nothing to do. + // Everything already in order? Nothing to do. if (mapping.length === 0) { return list } @@ -354,7 +354,7 @@ function max(nums) { * Using `.sort()` without a custom compare function is faster * But you can only use that if you're sorting an array of * only strings. If you're sorting strings inside objects - * or arrays, you need must use a custom compare function. + * or arrays, you need to use a custom compare function. * * @param {string} a * @param {string} b diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js new file mode 100644 index 000000000..624fa7030 --- /dev/null +++ b/src/lib/parseCssConfig.js @@ -0,0 +1,205 @@ +// @ts-check + +/** + * @typedef {[plugin: string|null, key: string[]|null, option: string|null]} ConfigPath + */ + +export class CssBasedConfig { + constructor() { + this.config = {} + } + + /** + * Find and convert the `:theme` rule to a configuration object + * This is merged with the user's JS config + * It should take precedence over the JS config + * + * @param {import('postcss').Root} root + * @returns {*} + */ + parse(root) { + this.config = { extend: {} } + + let rules = this.getThemeRules(root) + + rules.forEach(rule => { + rule.walkDecls((decl) => { + if (!decl.prop.startsWith('--')) { + throw decl.error('Only CSS variables are allowed in `:theme`') + } + + this.parseVariable(decl) + }) + + // Allow the variables to be used with var() anywhere in CSS + rule.selector = ':root' + }) + + return this.config + } + + /** + * Walk the tree and find all `:theme` rules + * + * @param {import('postcss').Root} root + * @returns {import('postcss').Rule[]} + */ + getThemeRules(root) { + /** @type {any[]} */ + let rules = root.nodes.filter(node => node.type === 'rule' && node.selector === ':theme') + + return rules + } + + /** + * Parse a variable declaration and modify the config + * + * @param {import('postcss').Declaration} decl + */ + parseVariable(decl) { + let config = this.config + + // Parse the variable name into a config plugin and keypath + let [name, value] = [decl.prop.slice(2), decl.value] + let [plugin, keypath, option] = this.parseVariableName(name) + + if (plugin === null) { + // We couldn't find a plugin for this variable, so we can't do anything with it + // This also means there is no reason to keep the variable in the CSS + decl.remove() + return + } + + if (keypath === null && value === 'unset') { + // when using `--some-plugin: unset` we want to reset whatever the default value is + config[plugin] = {} + + // This also means there is no reason to keep the variable in the CSS + decl.remove() + + return + } + + if (keypath !== null && value === 'unset') { + // when using `--plugin-key: unset` we want to remove that from the config + throw decl.error("Not implemented yet"); + } + + // TODO: Can this happen + if (keypath === null) { + return + } + + // All other cases are config keys in a plugin + config.extend[plugin] ??= {} + + let [path, key] = [ + keypath.slice(0, -1), + keypath[keypath.length-1], + ] + + let obj = config.extend[plugin] + let segment + while (segment = path.shift()) { + obj[segment] ??= {} + obj = obj[segment] + } + + if (option) { + // TODO: This is weird + if (!Array.isArray(obj[key])) { + obj[key] = [obj[key], {}] + } + + obj[key][1][option] = value + } else { + obj[key] = value + } + } + + /** + * Convert a variable name into: + * - The associated plugin + * - A keypath to modify inside plugin's config (if available) + * - An "option" which is a key into the "options" object when a Tuple-like value is used + * + * @param {string} name + * @returns {ConfigPath} + */ + parseVariableName(name) { + // Unescape the name if needed + // This is needed for CSS variables that contain special characters + name = unescape(name) + + for (const [prefix, plugin] of Object.entries(this.prefixPluginMap)) { + if (!name.startsWith(prefix)) continue + + // The keypath is the part of the variable name after the prefix + let keypath = name.slice(prefix.length) + let option = null + + let optionStart = keypath.indexOf('--') + if (optionStart !== -1) { + option = keypath.slice(optionStart+2) + keypath = keypath.slice(0, optionStart) + } + + if (keypath == '' && option === 'default') { + keypath = 'DEFAULT' + option = null + } else if (keypath.startsWith('-')) { + keypath = keypath.slice(1) + } + + if (keypath === '') { + return [plugin, null, null] + } + + option = option === null ? null : camelize(option); + + if (plugin === 'colors') { + return [plugin, keypath.split('-'), option] + } + + return [plugin, [keypath], option] + } + + return [null, null, null] + } + + get prefixPluginMap() { + // TODO: Maybe build this based on a list of registered plugins + // Or maybe a plugin can register namespaces themselves? + return { + 'animation': 'animation', + 'colors': 'colors', + 'spacing': 'spacing', + 'font-family': 'fontFamily', + 'font-size': 'fontSize', + // 'shadow': 'boxShadow', + 'blur': 'blur', + } + } +} + +/** + * @param {string} str + * @returns {string} + */ +function camelize(str) { + return str.replace(/-([a-zA-Z])/g, (v) => v.slice(1).toUpperCase()) +} + +/** + * @param {string} str + * @returns {string} + */ +function unescape(str) { + let pattern = /\\([0-9a-fA-F]{1,6}[\t\n\f\r ]?|[\S\s])/g + + return str.replace(pattern, (match) => + match.length > 2 + ? String.fromCodePoint(parseInt(match.slice(1).trimEnd(), 16)) + : match[1] + ) +} diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 0749da68d..0d6bc2509 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -21,7 +21,6 @@ import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPrope import { generateRules, getClassNameFromSelector } from './generateRules' import { hasContentChanged } from './cacheInvalidation.js' import { Offsets } from './offsets.js' -import { flagEnabled } from '../featureFlags.js' import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector' const VARIANT_TYPES = { @@ -434,10 +433,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs }, } - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let ruleSets = [] - .concat(modifiersEnabled ? rule(value, extras) : rule(value)) + .concat(rule(value, extras)) .filter(Boolean) .map((declaration) => ({ [nameClass(identifier, modifier)]: declaration, @@ -514,10 +511,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs }, } - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let ruleSets = [] - .concat(modifiersEnabled ? rule(value, extras) : rule(value)) + .concat(rule(value, extras)) .filter(Boolean) .map((declaration) => ({ [nameClass(identifier, modifier)]: declaration, @@ -585,18 +580,13 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs let id = options?.id ?? ++variantIdentifier let isSpecial = variant === '@' - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - for (let [key, value] of Object.entries(options?.values ?? {})) { if (key === 'DEFAULT') continue api.addVariant( isSpecial ? `${variant}${key}` : `${variant}-${key}`, ({ args, container }) => { - return variantFn( - value, - modifiersEnabled ? { modifier: args?.modifier, container } : { container } - ) + return variantFn(value, { modifier: args?.modifier, container }) }, { @@ -624,7 +614,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs : // Falling back to args if it is a string, otherwise '' for older intellisense // (JetBrains) plugins. args?.value ?? (typeof args === 'string' ? args : ''), - modifiersEnabled ? { modifier: args?.modifier, container } : { container } + { modifier: args?.modifier, container } ) }, { @@ -729,7 +719,7 @@ function collectLayerPlugins(root) { } function resolvePlugins(context, root) { - let corePluginList = Object.entries({ ...variantPlugins, ...corePlugins }) + let corePluginList = Object.entries(corePlugins) .map(([name, plugin]) => { if (!context.tailwindConfig.corePlugins.includes(name)) { return null @@ -754,6 +744,7 @@ function resolvePlugins(context, root) { let beforeVariants = [ variantPlugins['pseudoElementVariants'], variantPlugins['pseudoClassVariants'], + variantPlugins['hasVariants'], variantPlugins['ariaVariants'], variantPlugins['dataVariants'], ] diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index 2b281377d..550914be0 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -12,6 +12,7 @@ import { validateConfig } from '../util/validateConfig.js' import { parseCandidateFiles, resolvedChangedContent } from './content.js' import { loadConfig } from '../lib/load-config' import getModuleDependencies from './getModuleDependencies' +import { CssBasedConfig } from './parseCssConfig.js' let configPathCache = new LRU({ maxSize: 100 }) @@ -28,7 +29,7 @@ function getCandidateFiles(context, tailwindConfig) { } // Get the config object based on a path -function getTailwindConfig(configOrPath) { +function getTailwindConfig(configOrPath, cssThemeValues = {}) { let userConfigPath = resolveConfigPath(configOrPath) if (userConfigPath !== null) { @@ -56,7 +57,9 @@ function getTailwindConfig(configOrPath) { for (let file of newDeps) { delete require.cache[file] } - let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath))) + let newConfig = validateConfig( + resolveConfig(loadConfig(userConfigPath), { theme: cssThemeValues }) + ) let newHash = hash(newConfig) configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified]) return [newConfig, userConfigPath, newHash, newDeps] @@ -64,7 +67,8 @@ function getTailwindConfig(configOrPath) { // It's a plain object, not a path let newConfig = resolveConfig( - configOrPath.config === undefined ? configOrPath : configOrPath.config + configOrPath?.config ?? configOrPath ?? {}, + { theme: cssThemeValues } ) newConfig = validateConfig(newConfig) @@ -80,8 +84,11 @@ function getTailwindConfig(configOrPath) { export default function setupTrackingContext(configOrPath) { return ({ tailwindDirectives, registerDependency }) => { return (root, result) => { + // Parse any CSS-based config values from `:theme` rules + let cssThemeValues = new CssBasedConfig().parse(root) + let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = - getTailwindConfig(configOrPath) + getTailwindConfig(configOrPath, cssThemeValues) let contextDependencies = new Set(configDependencies) diff --git a/src/lib/sharedState.js b/src/lib/sharedState.js index 97bdf09c5..915dd21cb 100644 --- a/src/lib/sharedState.js +++ b/src/lib/sharedState.js @@ -1,16 +1,12 @@ -import pkg from '../../package.json' - export const env = typeof process !== 'undefined' ? { NODE_ENV: process.env.NODE_ENV, DEBUG: resolveDebug(process.env.DEBUG), - ENGINE: pkg.tailwindcss.engine, } : { NODE_ENV: 'production', DEBUG: false, - ENGINE: pkg.tailwindcss.engine, } export const contextMap = new Map() diff --git a/src/oxide/cli.ts b/src/oxide/cli.ts deleted file mode 100644 index 17552ecb1..000000000 --- a/src/oxide/cli.ts +++ /dev/null @@ -1 +0,0 @@ -import './cli/index' diff --git a/src/oxide/cli/build/deps.ts b/src/oxide/cli/build/deps.ts deleted file mode 100644 index 2b4355b17..000000000 --- a/src/oxide/cli/build/deps.ts +++ /dev/null @@ -1,91 +0,0 @@ -import packageJson from '../../../../package.json' -import browserslist from 'browserslist' -import { Result } from 'postcss' - -import { - // @ts-ignore - lazyPostcss, - - // @ts-ignore - lazyPostcssImport, - - // @ts-ignore - lazyCssnano, - - // @ts-ignore -} from '../../../../peers/index' - -export function lazyLightningCss() { - // TODO: Make this lazy/bundled - return require('lightningcss') -} - -let lightningCss - -function loadLightningCss() { - if (lightningCss) { - return lightningCss - } - - // Try to load a local version first - try { - return (lightningCss = require('lightningcss')) - } catch {} - - return (lightningCss = lazyLightningCss()) -} - -export async function lightningcss(shouldMinify: boolean, result: Result) { - let css = loadLightningCss() - - try { - let transformed = css.transform({ - filename: result.opts.from || 'input.css', - code: Buffer.from(result.css, 'utf-8'), - minify: shouldMinify, - sourceMap: !!result.map, - inputSourceMap: result.map ? result.map.toString() : undefined, - targets: css.browserslistToTargets(browserslist(packageJson.browserslist)), - drafts: { - nesting: true, - }, - }) - - return Object.assign(result, { - css: transformed.code.toString('utf8'), - map: result.map - ? Object.assign(result.map, { - toString() { - return transformed.map.toString() - }, - }) - : result.map, - }) - } catch (err) { - console.error('Unable to use Lightning CSS. Using raw version instead.') - console.error(err) - - return result - } -} - -/** - * @returns {import('postcss')} - */ -export function loadPostcss() { - // Try to load a local `postcss` version first - try { - return require('postcss') - } catch {} - - return lazyPostcss() -} - -export function loadPostcssImport() { - // Try to load a local `postcss-import` version first - try { - return require('postcss-import') - } catch {} - - return lazyPostcssImport() -} diff --git a/src/oxide/cli/build/index.ts b/src/oxide/cli/build/index.ts deleted file mode 100644 index ba7c87459..000000000 --- a/src/oxide/cli/build/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { resolveDefaultConfigPath } from '../../../util/resolveConfigPath' -import { createProcessor } from './plugin' - -export async function build(args) { - let input = args['--input'] - let shouldWatch = args['--watch'] - - // TODO: Deprecate this in future versions - if (!input && args['_'][1]) { - console.error('[deprecation] Running tailwindcss without -i, please provide an input file.') - input = args['--input'] = args['_'][1] - } - - if (input && input !== '-' && !fs.existsSync((input = path.resolve(input)))) { - console.error(`Specified input file ${args['--input']} does not exist.`) - process.exit(9) - } - - if (args['--config'] && !fs.existsSync((args['--config'] = path.resolve(args['--config'])))) { - console.error(`Specified config file ${args['--config']} does not exist.`) - process.exit(9) - } - - // TODO: Reference the @config path here if exists - let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath() - - let processor = await createProcessor(args, configPath) - - if (shouldWatch) { - // 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', () => process.exit(0)) - } - - process.stdin.resume() - - await processor.watch() - } else { - await processor.build().catch((e) => { - console.error(e) - process.exit(1) - }) - } -} diff --git a/src/oxide/cli/build/plugin.ts b/src/oxide/cli/build/plugin.ts deleted file mode 100644 index 4141ec439..000000000 --- a/src/oxide/cli/build/plugin.ts +++ /dev/null @@ -1,442 +0,0 @@ -import path from 'path' -import fs from 'fs' -import postcssrc from 'postcss-load-config' -import { lilconfig } from 'lilconfig' -import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API -import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API - -import tailwind from '../../../processTailwindFeatures' -import { loadPostcss, loadPostcssImport, lightningcss } from './deps' -import { formatNodes, drainStdin, outputFile } from './utils' -import { env } from '../../../lib/sharedState' -import resolveConfig from '../../../../resolveConfig' -import { parseCandidateFiles } from '../../../lib/content' -import { createWatcher } from './watching' -import fastGlob from 'fast-glob' -import { findAtConfigPath } from '../../../lib/findAtConfigPath' -import log from '../../../util/log' -import { loadConfig } from '../../../lib/load-config' -import getModuleDependencies from '../../../lib/getModuleDependencies' -import type { Config } from '../../../../types' - -/** - * - * @param {string} [customPostCssPath ] - * @returns - */ -async function loadPostCssPlugins(customPostCssPath) { - let config = customPostCssPath - ? await (async () => { - let file = path.resolve(customPostCssPath) - - // Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js - // @ts-ignore - let { config = {} } = await lilconfig('postcss').load(file) - if (typeof config === 'function') { - config = config() - } else { - config = Object.assign({}, config) - } - - if (!config.plugins) { - config.plugins = [] - } - - return { - file, - plugins: loadPlugins(config, file), - options: loadOptions(config, file), - } - })() - : await postcssrc() - - let configPlugins = config.plugins - - let configPluginTailwindIdx = configPlugins.findIndex((plugin) => { - if (typeof plugin === 'function' && plugin.name === 'tailwindcss') { - return true - } - - if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') { - return true - } - - return false - }) - - let beforePlugins = - configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx) - let afterPlugins = - configPluginTailwindIdx === -1 - ? configPlugins - : configPlugins.slice(configPluginTailwindIdx + 1) - - return [beforePlugins, afterPlugins, config.options] -} - -function loadBuiltinPostcssPlugins() { - let postcss = loadPostcss() - let IMPORT_COMMENT = '__TAILWIND_RESTORE_IMPORT__: ' - return [ - [ - (root) => { - root.walkAtRules('import', (rule) => { - if (rule.params.slice(1).startsWith('tailwindcss/')) { - rule.after(postcss.comment({ text: IMPORT_COMMENT + rule.params })) - rule.remove() - } - }) - }, - loadPostcssImport(), - (root) => { - root.walkComments((rule) => { - if (rule.text.startsWith(IMPORT_COMMENT)) { - rule.after( - postcss.atRule({ - name: 'import', - params: rule.text.replace(IMPORT_COMMENT, ''), - }) - ) - rule.remove() - } - }) - }, - ], - [], - {}, - ] -} - -let state = { - /** @type {any} */ - context: null, - - /** @type {ReturnType | null} */ - watcher: null, - - /** @type {{content: string, extension: string}[]} */ - changedContent: [], - - /** @type {{config: Config, dependencies: Set, dispose: Function } | null} */ - configBag: null, - - contextDependencies: new Set(), - - /** @type {import('../../lib/content.js').ContentPath[]} */ - contentPaths: [], - - refreshContentPaths() { - this.contentPaths = parseCandidateFiles(this.context, this.context?.tailwindConfig) - }, - - get config() { - return this.context.tailwindConfig - }, - - get contentPatterns() { - return { - all: this.contentPaths.map((contentPath) => contentPath.pattern), - dynamic: this.contentPaths - .filter((contentPath) => contentPath.glob !== undefined) - .map((contentPath) => contentPath.pattern), - } - }, - - loadConfig(configPath, content) { - if (this.watcher && configPath) { - this.refreshConfigDependencies() - } - - let config = loadConfig(configPath) - let dependencies = getModuleDependencies(configPath) - this.configBag = { - config, - dependencies, - dispose() { - for (let file of dependencies) { - delete require.cache[require.resolve(file)] - } - }, - } - - // @ts-ignore - this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } }) - - // Override content files if `--content` has been passed explicitly - if (content?.length > 0) { - this.configBag.config.content.files = content - } - - return this.configBag.config - }, - - refreshConfigDependencies(configPath) { - env.DEBUG && console.time('Module dependencies') - this.configBag?.dispose() - env.DEBUG && console.timeEnd('Module dependencies') - }, - - readContentPaths() { - let content = [] - - // Resolve globs from the content config - // TODO: When we make the postcss plugin async-capable this can become async - let files = fastGlob.sync(this.contentPatterns.all) - - for (let file of files) { - if (__OXIDE__) { - content.push({ - file, - extension: path.extname(file).slice(1), - }) - } else { - content.push({ - content: fs.readFileSync(path.resolve(file), 'utf8'), - extension: path.extname(file).slice(1), - }) - } - } - - // Resolve raw content in the tailwind config - let rawContent = this.config.content.files.filter((file) => { - return file !== null && typeof file === 'object' - }) - - for (let { raw: htmlContent, extension = 'html' } of rawContent) { - content.push({ content: htmlContent, extension }) - } - - return content - }, - - getContext({ createContext, cliConfigPath, root, result, content }) { - if (this.context) { - this.context.changedContent = this.changedContent.splice(0) - - return this.context - } - - env.DEBUG && console.time('Searching for config') - let configPath = findAtConfigPath(root, result) ?? cliConfigPath - env.DEBUG && console.timeEnd('Searching for config') - - env.DEBUG && console.time('Loading config') - let config = this.loadConfig(configPath, content) - env.DEBUG && console.timeEnd('Loading config') - - env.DEBUG && console.time('Creating context') - this.context = createContext(config, []) - Object.assign(this.context, { - userConfigPath: configPath, - }) - env.DEBUG && console.timeEnd('Creating context') - - env.DEBUG && console.time('Resolving content paths') - this.refreshContentPaths() - env.DEBUG && console.timeEnd('Resolving content paths') - - if (this.watcher) { - env.DEBUG && console.time('Watch new files') - this.watcher.refreshWatchedFiles() - env.DEBUG && console.timeEnd('Watch new files') - } - - for (let file of this.readContentPaths()) { - this.context.changedContent.push(file) - } - - return this.context - }, -} - -export async function createProcessor(args, cliConfigPath) { - let postcss = loadPostcss() - - let input = args['--input'] - let output = args['--output'] - let includePostCss = args['--postcss'] - let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined - - let [beforePlugins, afterPlugins, postcssOptions] = includePostCss - ? await loadPostCssPlugins(customPostCssPath) - : loadBuiltinPostcssPlugins() - - if (args['--purge']) { - log.warn('purge-flag-deprecated', [ - 'The `--purge` flag has been deprecated.', - 'Please use `--content` instead.', - ]) - - if (!args['--content']) { - args['--content'] = args['--purge'] - } - } - - let content = args['--content']?.split(/(? { - return { - postcssPlugin: 'tailwindcss', - Once(root, { result }) { - env.DEBUG && console.time('Compiling CSS') - tailwind(({ createContext }) => { - console.error() - console.error('Rebuilding...') - - return () => { - return state.getContext({ - createContext, - cliConfigPath, - root, - result, - content, - }) - } - })(root, result) - env.DEBUG && console.timeEnd('Compiling CSS') - }, - } - } - - tailwindPlugin.postcss = true - - let plugins = [ - ...beforePlugins, - tailwindPlugin, - !args['--minify'] && formatNodes, - ...afterPlugins, - ].filter(Boolean) - - /** @type {import('postcss').Processor} */ - // @ts-ignore - let processor = postcss(plugins) - - async function readInput() { - // Piping in data, let's drain the stdin - if (input === '-') { - return drainStdin() - } - - // Input file has been provided - if (input) { - return fs.promises.readFile(path.resolve(input), 'utf8') - } - - // No input file provided, fallback to default atrules - return '@tailwind base; @tailwind components; @tailwind utilities' - } - - async function build() { - let start = process.hrtime.bigint() - - return readInput() - .then((css) => processor.process(css, { ...postcssOptions, from: input, to: output })) - .then((result) => lightningcss(!!args['--minify'], result)) - .then((result) => { - if (!state.watcher) { - return result - } - - env.DEBUG && console.time('Recording PostCSS dependencies') - for (let message of result.messages) { - if (message.type === 'dependency') { - state.contextDependencies.add(message.file) - } - } - env.DEBUG && console.timeEnd('Recording PostCSS dependencies') - - // TODO: This needs to be in a different spot - env.DEBUG && console.time('Watch new files') - state.watcher.refreshWatchedFiles() - env.DEBUG && console.timeEnd('Watch new files') - - return result - }) - .then((result) => { - if (!output) { - process.stdout.write(result.css) - return - } - - return Promise.all([ - outputFile(result.opts.to, result.css), - result.map && outputFile(result.opts.to + '.map', result.map.toString()), - ]) - }) - .then(() => { - let end = process.hrtime.bigint() - console.error() - console.error('Done in', (end - start) / BigInt(1e6) + 'ms.') - }) - .then( - () => {}, - (err) => { - // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies - // that were collected before the error occurred - // The result is not stored on the error so we have to store it externally - // and pull the messages off of it here somehow - - // This results in a less than ideal DX because the watcher will not pick up - // changes to imported CSS if one of them caused an error during the initial build - // If you fix it and then save the main CSS file so there's no error - // The watcher will start watching the imported CSS files and will be - // resilient to future errors. - - if (state.watcher) { - console.error(err) - } else { - return Promise.reject(err) - } - } - ) - } - - /** - * @param {{file: string, content(): Promise, extension: string}[]} changes - */ - async function parseChanges(changes) { - return Promise.all( - changes.map(async (change) => ({ - content: await change.content(), - extension: change.extension, - })) - ) - } - - if (input !== undefined && input !== '-') { - state.contextDependencies.add(path.resolve(input)) - } - - return { - build, - watch: async () => { - state.watcher = createWatcher(args, { - state, - - /** - * @param {{file: string, content(): Promise, extension: string}[]} changes - */ - async rebuild(changes) { - let needsNewContext = changes.some((change) => { - return ( - state.configBag?.dependencies.has(change.file) || - state.contextDependencies.has(change.file) - ) - }) - - if (needsNewContext) { - state.context = null - } else { - for (let change of await parseChanges(changes)) { - state.changedContent.push(change) - } - } - - return build() - }, - }) - - await build() - }, - } -} diff --git a/src/oxide/cli/build/utils.ts b/src/oxide/cli/build/utils.ts deleted file mode 100644 index 001857a91..000000000 --- a/src/oxide/cli/build/utils.ts +++ /dev/null @@ -1,74 +0,0 @@ -import fs from 'fs' -import path from 'path' - -export function indentRecursive(node, indent = 0) { - node.each && - node.each((child, i) => { - if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) { - child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}` - } - child.raws.after = `\n${' '.repeat(indent)}` - indentRecursive(child, indent + 1) - }) -} - -export function formatNodes(root) { - indentRecursive(root) - if (root.first) { - root.first.raws.before = '' - } -} - -/** - * When rapidly saving files atomically a couple of situations can happen: - * - The file is missing since the external program has deleted it by the time we've gotten around to reading it from the earlier save. - * - The file is being written to by the external program by the time we're going to read it and is thus treated as busy because a lock is held. - * - * To work around this we retry reading the file a handful of times with a delay between each attempt - * - * @param {string} path - * @param {number} tries - * @returns {Promise} - * @throws {Error} If the file is still missing or busy after the specified number of tries - */ -export async function readFileWithRetries(path, tries = 5) { - for (let n = 0; n <= tries; n++) { - try { - return await fs.promises.readFile(path, 'utf8') - } catch (err) { - if (n !== tries) { - if (err.code === 'ENOENT' || err.code === 'EBUSY') { - await new Promise((resolve) => setTimeout(resolve, 10)) - - continue - } - } - - throw err - } - } -} - -export 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 outputFile(file, newContents) { - try { - let currentContents = await fs.promises.readFile(file, 'utf8') - if (currentContents === newContents) { - return // Skip writing the file - } - } catch {} - - // Write the file - await fs.promises.mkdir(path.dirname(file), { recursive: true }) - await fs.promises.writeFile(file, newContents, 'utf8') -} diff --git a/src/oxide/cli/build/watching.ts b/src/oxide/cli/build/watching.ts deleted file mode 100644 index 9d5680a16..000000000 --- a/src/oxide/cli/build/watching.ts +++ /dev/null @@ -1,225 +0,0 @@ -import chokidar from 'chokidar' -import fs from 'fs' -import micromatch from 'micromatch' -import normalizePath from 'normalize-path' -import path from 'path' - -import { readFileWithRetries } from './utils' - -/** - * The core idea of this watcher is: - * 1. Whenever a file is added, changed, or renamed we queue a rebuild - * 2. Perform as few rebuilds as possible by batching them together - * 3. Coalesce events that happen in quick succession to avoid unnecessary rebuilds - * 4. Ensure another rebuild happens _if_ changed while a rebuild is in progress - */ - -/** - * - * @param {*} args - * @param {{ state, rebuild(changedFiles: any[]): Promise }} param1 - * @returns {{ - * fswatcher: import('chokidar').FSWatcher, - * refreshWatchedFiles(): void, - * }} - */ -export function createWatcher(args, { state, rebuild }) { - let shouldPoll = args['--poll'] - let shouldCoalesceWriteEvents = shouldPoll || process.platform === 'win32' - - // Polling interval in milliseconds - // Used only when polling or coalescing add/change events on Windows - let pollInterval = 10 - - let watcher = chokidar.watch([], { - // Force checking for atomic writes in all situations - // This causes chokidar to wait up to 100ms for a file to re-added after it's been unlinked - // This only works when watching directories though - atomic: true, - - usePolling: shouldPoll, - interval: shouldPoll ? pollInterval : undefined, - ignoreInitial: true, - awaitWriteFinish: shouldCoalesceWriteEvents - ? { - stabilityThreshold: 50, - pollInterval: pollInterval, - } - : false, - }) - - // A queue of rebuilds, file reads, etc… to run - let chain = Promise.resolve() - - /** - * A list of files that have been changed since the last rebuild - * - * @type {{file: string, content: () => Promise, extension: string}[]} - */ - let changedContent = [] - - /** - * A list of files for which a rebuild has already been queued. - * This is used to prevent duplicate rebuilds when multiple events are fired for the same file. - * The rebuilt file is cleared from this list when it's associated rebuild has _started_ - * This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should - **/ - let pendingRebuilds = new Set() - - let _timer - let _reject - - /** - * Rebuilds the changed files and resolves when the rebuild is - * complete regardless of whether it was successful or not - */ - async function rebuildAndContinue() { - let changes = changedContent.splice(0) - - // There are no changes to rebuild so we can just do nothing - if (changes.length === 0) { - return Promise.resolve() - } - - // Clear all pending rebuilds for the about-to-be-built files - changes.forEach((change) => pendingRebuilds.delete(change.file)) - - // Resolve the promise even when the rebuild fails - return rebuild(changes).then( - () => {}, - () => {} - ) - } - - /** - * - * @param {*} file - * @param {(() => Promise) | null} content - * @param {boolean} skipPendingCheck - * @returns {Promise} - */ - function recordChangedFile(file, content = null, skipPendingCheck = false) { - file = path.resolve(file) - - // Applications like Vim/Neovim fire both rename and change events in succession for atomic writes - // In that case rebuild has already been queued by rename, so can be skipped in change - if (pendingRebuilds.has(file) && !skipPendingCheck) { - return Promise.resolve() - } - - // Mark that a rebuild of this file is going to happen - // It MUST happen synchronously before the rebuild is queued for this to be effective - pendingRebuilds.add(file) - - changedContent.push({ - file, - content: content ?? (() => fs.promises.readFile(file, 'utf8')), - extension: path.extname(file).slice(1), - }) - - if (_timer) { - clearTimeout(_timer) - _reject() - } - - // If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired - chain = chain.then( - () => - new Promise((resolve, reject) => { - _timer = setTimeout(resolve, 10) - _reject = reject - }) - ) - - // Resolves once this file has been rebuilt (or the rebuild for this file has failed) - // This queues as many rebuilds as there are changed files - // But those rebuilds happen after some delay - // And will immediately resolve if there are no changes - chain = chain.then(rebuildAndContinue, rebuildAndContinue) - - return chain - } - - watcher.on('change', (file) => recordChangedFile(file)) - watcher.on('add', (file) => recordChangedFile(file)) - - // Restore watching any files that are "removed" - // This can happen when a file is pseudo-atomically replaced (a copy is created, overwritten, the old one is unlinked, and the new one is renamed) - // TODO: An an optimization we should allow removal when the config changes - watcher.on('unlink', (file) => { - file = normalizePath(file) - - // Only re-add the file if it's not covered by a dynamic pattern - if (!micromatch.some([file], state.contentPatterns.dynamic)) { - watcher.add(file) - } - }) - - // Some applications such as Visual Studio (but not VS Code) - // will only fire a rename event for atomic writes and not a change event - // This is very likely a chokidar bug but it's one we need to work around - // We treat this as a change event and rebuild the CSS - watcher.on('raw', (evt, filePath, meta) => { - if (evt !== 'rename') { - return - } - - let watchedPath = meta.watchedPath - - // Watched path might be the file itself - // Or the directory it is in - filePath = watchedPath.endsWith(filePath) ? watchedPath : path.join(watchedPath, filePath) - - // Skip this event since the files it is for does not match any of the registered content globs - if (!micromatch.some([filePath], state.contentPatterns.all)) { - return - } - - // Skip since we've already queued a rebuild for this file that hasn't happened yet - if (pendingRebuilds.has(filePath)) { - return - } - - // We'll go ahead and add the file to the pending rebuilds list here - // It'll be removed when the rebuild starts unless the read fails - // which will be taken care of as well - pendingRebuilds.add(filePath) - - async function enqueue() { - try { - // We need to read the file as early as possible outside of the chain - // because it may be gone by the time we get to it. doing the read - // immediately increases the chance that the file is still there - let content = await readFileWithRetries(path.resolve(filePath)) - - if (content === undefined) { - return - } - - // This will push the rebuild onto the chain - // We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux - // This is because the order of events and timing is different on Linux - // @ts-ignore: TypeScript isn't picking up that content is a string here - await recordChangedFile(filePath, () => content, true) - } catch { - // If reading the file fails, it's was probably a deleted temporary file - // So we can ignore it and no rebuild is needed - } - } - - enqueue().then(() => { - // If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list - pendingRebuilds.delete(filePath) - }) - }) - - return { - fswatcher: watcher, - - refreshWatchedFiles() { - watcher.add(Array.from(state.contextDependencies)) - watcher.add(Array.from(state.configBag.dependencies)) - watcher.add(state.contentPatterns.all) - }, - } -} diff --git a/src/oxide/cli/help/index.ts b/src/oxide/cli/help/index.ts deleted file mode 100644 index c36042a65..000000000 --- a/src/oxide/cli/help/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import packageJson from '../../../../package.json' - -export function help({ message, usage, commands, options }) { - let indent = 2 - - // Render header - console.log() - console.log(`${packageJson.name} v${packageJson.version}`) - - // Render message - if (message) { - console.log() - for (let msg of message.split('\n')) { - console.log(msg) - } - } - - // Render usage - if (usage && usage.length > 0) { - console.log() - console.log('Usage:') - for (let example of usage) { - console.log(' '.repeat(indent), example) - } - } - - // Render commands - if (commands && commands.length > 0) { - console.log() - console.log('Commands:') - for (let command of commands) { - console.log(' '.repeat(indent), command) - } - } - - // Render options - if (options) { - let groupedOptions = {} - for (let [key, value] of Object.entries(options)) { - if (typeof value === 'object') { - groupedOptions[key] = { ...value, flags: [key] } - } else { - groupedOptions[value].flags.push(key) - } - } - - console.log() - console.log('Options:') - for (let { flags, description, deprecated } of Object.values(groupedOptions)) { - if (deprecated) continue - - if (flags.length === 1) { - console.log( - ' '.repeat(indent + 4 /* 4 = "-i, ".length */), - flags.slice().reverse().join(', ').padEnd(20, ' '), - description - ) - } else { - console.log( - ' '.repeat(indent), - flags.slice().reverse().join(', ').padEnd(24, ' '), - description - ) - } - } - } - - console.log() -} diff --git a/src/oxide/cli/index.ts b/src/oxide/cli/index.ts deleted file mode 100644 index 96b284db9..000000000 --- a/src/oxide/cli/index.ts +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env node - -import path from 'path' -import arg from 'arg' -import fs from 'fs' - -import { build } from './build' -import { help } from './help' -import { init } from './init' - -// --- - -function oneOf(...options) { - return Object.assign( - (value = true) => { - for (let option of options) { - let parsed = option(value) - if (parsed === value) { - return parsed - } - } - - throw new Error('...') - }, - { manualParsing: true } - ) -} - -let commands = { - init: { - run: init, - args: { - '--esm': { type: Boolean, description: `Initialize configuration file as ESM` }, - '--ts': { type: Boolean, description: `Initialize configuration file as TypeScript` }, - '--full': { - type: Boolean, - description: `Include the default values for all options in the generated configuration file`, - }, - '-f': '--full', - }, - }, - build: { - run: build, - args: { - '--input': { type: String, description: 'Input file' }, - '--output': { type: String, description: 'Output file' }, - '--watch': { - type: oneOf(String, Boolean), - description: 'Watch for changes and rebuild as needed', - }, - '--poll': { - type: Boolean, - description: 'Use polling instead of filesystem events when watching', - }, - '--content': { - type: String, - description: 'Content paths to use for removing unused classes', - }, - '--minify': { type: Boolean, description: 'Minify the output' }, - '--config': { - type: String, - description: 'Path to a custom config file', - }, - '-c': '--config', - '-i': '--input', - '-o': '--output', - '-m': '--minify', - '-w': '--watch', - '-p': '--poll', - }, - }, -} - -let sharedFlags = { - '--help': { type: Boolean, description: 'Display usage information' }, - '-h': '--help', -} - -if ( - process.stdout.isTTY /* Detect redirecting output to a file */ && - (process.argv[2] === undefined || - process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined)) -) { - help({ - usage: [ - 'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]', - 'tailwindcss init [--full] [options...]', - ], - commands: Object.keys(commands) - .filter((command) => command !== 'build') - .map((command) => `${command} [options]`), - options: { ...commands.build.args, ...sharedFlags }, - }) - process.exit(0) -} - -let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build' - -if (commands[command] === undefined) { - if (fs.existsSync(path.resolve(command))) { - // TODO: Deprecate this in future versions - // Check if non-existing command, might be a file. - command = 'build' - } else { - help({ - message: `Invalid command: ${command}`, - usage: ['tailwindcss [options]'], - commands: Object.keys(commands) - .filter((command) => command !== 'build') - .map((command) => `${command} [options]`), - options: sharedFlags, - }) - process.exit(1) - } -} - -// Execute command -let { args: flags, run } = commands[command] -let args = (() => { - try { - let result = arg( - Object.fromEntries( - Object.entries({ ...flags, ...sharedFlags }) - .filter(([_key, value]) => !value?.type?.manualParsing) - .map(([key, value]) => [key, typeof value === 'object' ? value.type : value]) - ), - { permissive: true } - ) - - // Manual parsing of flags to allow for special flags like oneOf(Boolean, String) - for (let i = result['_'].length - 1; i >= 0; --i) { - let flag = result['_'][i] - if (!flag.startsWith('-')) continue - - let [flagName, flagValue] = flag.split('=') - let handler = flags[flagName] - - // Resolve flagName & handler - while (typeof handler === 'string') { - flagName = handler - handler = flags[handler] - } - - if (!handler) continue - - let args = [] - let offset = i + 1 - - // --flag value syntax was used so we need to pull `value` from `args` - if (flagValue === undefined) { - // Parse args for current flag - while (result['_'][offset] && !result['_'][offset].startsWith('-')) { - args.push(result['_'][offset++]) - } - - // Cleanup manually parsed flags + args - result['_'].splice(i, 1 + args.length) - - // No args were provided, use default value defined in handler - // One arg was provided, use that directly - // Multiple args were provided so pass them all in an array - flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args - } else { - // Remove the whole flag from the args array - result['_'].splice(i, 1) - } - - // Set the resolved value in the `result` object - result[flagName] = handler.type(flagValue, flagName) - } - - // Ensure that the `command` is always the first argument in the `args`. - // This is important so that we don't have to check if a default command - // (build) was used or not from within each plugin. - // - // E.g.: tailwindcss input.css -> _: ['build', 'input.css'] - // E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] - if (result['_'][0] !== command) { - result['_'].unshift(command) - } - - return result - } catch (err) { - if (err.code === 'ARG_UNKNOWN_OPTION') { - help({ - message: err.message, - usage: ['tailwindcss [options]'], - options: sharedFlags, - }) - process.exit(1) - } - throw err - } -})() - -if (args['--help']) { - help({ - options: { ...flags, ...sharedFlags }, - usage: [`tailwindcss ${command} [options]`], - }) - process.exit(0) -} - -run(args) diff --git a/src/oxide/cli/init/index.ts b/src/oxide/cli/init/index.ts deleted file mode 100644 index abc93cdc1..000000000 --- a/src/oxide/cli/init/index.ts +++ /dev/null @@ -1,59 +0,0 @@ -import fs from 'fs' -import path from 'path' - -function isESM() { - const pkgPath = path.resolve('./package.json') - - try { - let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) - return pkg.type && pkg.type === 'module' - } catch (err) { - return false - } -} - -export function init(args) { - let messages: string[] = [] - - let isProjectESM = args['--ts'] || args['--esm'] || isESM() - let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs' - let extension = args['--ts'] ? 'ts' : 'js' - - let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./tailwind.config.${extension}`) - - if (fs.existsSync(tailwindConfigLocation)) { - messages.push(`${path.basename(tailwindConfigLocation)} already exists.`) - } else { - let stubContentsFile = fs.readFileSync( - args['--full'] - ? path.resolve(__dirname, '../../../../stubs/config.full.js') - : path.resolve(__dirname, '../../../../stubs/config.simple.js'), - 'utf8' - ) - - let stubFile = fs.readFileSync( - path.resolve(__dirname, `../../../../stubs/tailwind.config.${syntax}`), - 'utf8' - ) - - // Change colors import - stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') - - // Replace contents of {ts,js,cjs} file with the stub {simple,full}. - stubFile = - stubFile - .replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim()) - .trim() + '\n\n' - - fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8') - - messages.push(`Created Tailwind CSS config file: ${path.basename(tailwindConfigLocation)}`) - } - - if (messages.length > 0) { - console.log() - for (let message of messages) { - console.log(message) - } - } -} diff --git a/src/oxide/postcss-plugin.ts b/src/oxide/postcss-plugin.ts deleted file mode 100644 index 1be3203f9..000000000 --- a/src/oxide/postcss-plugin.ts +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../plugin.js') diff --git a/src/plugin.js b/src/plugin.js index 59f5fab01..4fcb058f3 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,7 +1,12 @@ +import postcss from 'postcss' +import lightningcss, { Features } from 'lightningcss' +import browserslist from 'browserslist' import setupTrackingContext from './lib/setupTrackingContext' import processTailwindFeatures from './processTailwindFeatures' import { env } from './lib/sharedState' import { findAtConfigPath } from './lib/findAtConfigPath' +import { handleImportAtRules } from './lib/handleImportAtRules' +import { CssBasedConfig } from './lib/parseCssConfig' module.exports = function tailwindcss(configOrPath) { return { @@ -13,6 +18,7 @@ module.exports = function tailwindcss(configOrPath) { console.time('JIT TOTAL') return root }, + ...handleImportAtRules(), function (root, result) { // Use the path for the `@config` directive if it exists, otherwise use the // path for the file being processed @@ -34,66 +40,82 @@ module.exports = function tailwindcss(configOrPath) { processTailwindFeatures(context)(root, result) }, - __OXIDE__ && - function lightningCssPlugin(_root, result) { - let postcss = require('postcss') - let lightningcss = require('lightningcss') - let browserslist = require('browserslist') + function lightningCssPlugin(_root, result) { + let map = result.map ?? result.opts.map - try { - let transformed = lightningcss.transform({ - filename: result.opts.from, - code: Buffer.from(result.root.toString()), - minify: false, - sourceMap: !!result.map, - inputSourceMap: result.map ? result.map.toString() : undefined, - targets: - typeof process !== 'undefined' && process.env.JEST_WORKER_ID - ? { chrome: 106 << 16 } - : lightningcss.browserslistToTargets( - browserslist(require('../package.json').browserslist) - ), + let intermediateResult = result.root.toResult({ + map: map ? { inline: true } : false, + }) - drafts: { - nesting: true, - customMedia: true, - }, - }) + let intermediateMap = intermediateResult.map?.toJSON?.() ?? map - result.map = Object.assign(result.map ?? {}, { - toJSON() { - return transformed.map.toJSON() - }, - toString() { - return transformed.map.toString() - }, - }) + try { + let resolvedBrowsersListConfig = browserslist.findConfig( + result.opts.from ?? process.cwd() + )?.defaults + let defaultBrowsersListConfig = require('../package.json').browserslist + let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig - result.root = postcss.parse(transformed.code.toString('utf8')) - } catch (err) { - if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { - let lines = err.source.split('\n') - err = new Error( - [ - 'Error formatting using Lightning CSS:', - '', - ...[ - '```css', - ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), - ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), - ...lines.slice(err.loc.line, err.loc.line + 2), - '```', - ], - ].join('\n') - ) + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(intermediateResult.css), + minify: false, + sourceMap: !!intermediateMap, + targets: lightningcss.browserslistToTargets(browserslist(browsersListConfig)), + drafts: { + nesting: true, + customMedia: true, + }, + nonStandard: { + deepSelectorCombinator: true, + }, + include: Features.Nesting, + exclude: Features.LogicalProperties, + }) + + let code = transformed.code.toString() + + // https://postcss.org/api/#sourcemapoptions + if (intermediateMap && transformed.map != null) { + let prev = transformed.map.toString() + + if (typeof intermediateMap === 'object') { + intermediateMap.prev = prev + } else { + code = `${code}\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from( + prev + ).toString('base64')} */` } - - if (Error.captureStackTrace) { - Error.captureStackTrace(err, lightningCssPlugin) - } - throw err } - }, + + result.root = postcss.parse(code, { + ...result.opts, + map: intermediateMap, + }) + } catch (err) { + if (err.source && typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { + let lines = err.source.split('\n') + err = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) + } + + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin) + } + throw err + } + }, env.DEBUG && function (root) { console.timeEnd('JIT TOTAL') diff --git a/src/processTailwindFeatures.js b/src/processTailwindFeatures.js index 952e17a13..7fac4272f 100644 --- a/src/processTailwindFeatures.js +++ b/src/processTailwindFeatures.js @@ -7,7 +7,7 @@ import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules' import collapseAdjacentRules from './lib/collapseAdjacentRules' import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations' import partitionApplyAtRules from './lib/partitionApplyAtRules' -import detectNesting from './lib/detectNesting' +// import detectNesting from './lib/detectNesting' import { createContext } from './lib/setupContextUtils' import { issueFlagNotices } from './featureFlags' @@ -15,7 +15,7 @@ export default function processTailwindFeatures(setupContext) { return function (root, result) { let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root) - detectNesting()(root, result) + // detectNesting()(root, result) // Partition apply rules that are found in the css // itself. diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js index 55cc00579..2f01aa3d2 100644 --- a/src/util/dataTypes.js +++ b/src/util/dataTypes.js @@ -49,10 +49,22 @@ export function normalize(value, isRoot = true) { value = value.trim() } - // Add spaces around operators inside math functions like calc() that do not follow an operator - // or '('. - value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { + value = normalizeMathOperatorSpacing(value) + + return value +} + +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator or '('. + * + * @param {string} value + * @returns {string} + */ +function normalizeMathOperatorSpacing(value) { + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { let vars = [] + return match .replace(/var\((--.+?)[,)]/g, (match, g1) => { vars.push(g1) @@ -61,8 +73,6 @@ export function normalize(value, isRoot = true) { .replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ') .replace(placeholderRe, () => vars.shift()) }) - - return value } export function url(value) { @@ -178,11 +188,12 @@ export function image(value) { } let gradientTypes = new Set([ + 'conic-gradient', 'linear-gradient', 'radial-gradient', + 'repeating-conic-gradient', 'repeating-linear-gradient', 'repeating-radial-gradient', - 'conic-gradient', ]) export function gradient(value) { value = normalize(value) diff --git a/src/util/log.js b/src/util/log.js index 0df5c8719..900c2d53f 100644 --- a/src/util/log.js +++ b/src/util/log.js @@ -17,6 +17,30 @@ export function dim(input) { } export default { + group(key, cb) { + if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return + + if (key && alreadyShown.has(key)) return + if (key) alreadyShown.add(key) + + console.warn('') + + cb({ + info(messages) { + messages.forEach((message) => console.warn(colors.bold(colors.cyan('info')), '-', message)) + }, + warn(messages) { + messages.forEach((message) => + console.warn(colors.bold(colors.yellow('warn')), '-', message) + ) + }, + risk(messages) { + messages.forEach((message) => + console.warn(colors.bold(colors.magenta('risk')), '-', message) + ) + }, + }) + }, info(key, messages) { log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key])) }, diff --git a/src/util/normalizeConfig.js b/src/util/normalizeConfig.js index 7e1a592de..edab3f466 100644 --- a/src/util/normalizeConfig.js +++ b/src/util/normalizeConfig.js @@ -1,4 +1,4 @@ -import { flagEnabled } from '../featureFlags' +import { flagEnabled, featureFlags } from '../featureFlags' import log, { dim } from './log' export function normalizeConfig(config) { @@ -18,6 +18,10 @@ export function normalizeConfig(config) { * } */ let valid = (() => { + if (config.content === 'auto') { + return true + } + // `config.purge` should not exist anymore if (config.purge) { return false @@ -196,11 +200,17 @@ export function normalizeConfig(config) { files: (() => { let { content, purge } = config - if (Array.isArray(purge)) return purge - if (Array.isArray(purge?.content)) return purge.content + if (content === undefined && purge === undefined) return [] + if (purge) { + if (Array.isArray(purge)) return purge + if (Array.isArray(purge?.content)) return purge.content + return [] + } + if (Array.isArray(content)) return content if (Array.isArray(content?.content)) return content.content if (Array.isArray(content?.files)) return content.files + if (content === 'auto') return ['auto'] return [] })(), @@ -284,16 +294,33 @@ export function normalizeConfig(config) { })(), } + // Force disable the `oxideParser` feature flag when using unsupported features. + // TODO: Remove once we have prefix or separator support in the oxide parser. + if (config.prefix !== '' || config.separator !== ':') { + if (config.experimental === 'all') { + config.experimental = {} + for (let key in featureFlags.experimental) { + config.experimental[key] = true + } + } else { + config.experimental = config.experimental ?? {} + } + + config.experimental.oxideParser = false + } + // Validate globs to prevent bogus globs. // E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html` - for (let file of config.content.files) { - if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) { - log.warn('invalid-glob-braces', [ - `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`, - `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`, - // TODO: Add https://tw.wtf/invalid-glob-braces - ]) - break + if (config.content.files !== 'auto') { + for (let file of config.content.files) { + if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) { + log.warn('invalid-glob-braces', [ + `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`, + `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`, + // TODO: Add https://tw.wtf/invalid-glob-braces + ]) + break + } } } diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index bef9fc165..d4df12286 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -18,7 +18,6 @@ import { } from './dataTypes' import negateValue from './negateValue' import { backgroundSize } from './validateFormalSyntax' -import { flagEnabled } from '../featureFlags.js' /** * @param {import('postcss-selector-parser').Container} selectors @@ -243,12 +242,9 @@ export function coerceValue(types, modifier, options, tailwindConfig) { * @returns {Iterator<[value: string, type: string, modifier: string | null]>} */ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) { - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let [modifier, utilityModifier] = splitUtilityModifier(rawModifier) let canUseUtilityModifier = - modifiersEnabled && options.modifiers != null && (options.modifiers === 'any' || (typeof options.modifiers === 'object' && diff --git a/src/util/pseudoElements.js b/src/util/pseudoElements.js index 9f0e54c67..5795cdd42 100644 --- a/src/util/pseudoElements.js +++ b/src/util/pseudoElements.js @@ -19,40 +19,37 @@ // **Jumpable** // Any terminal element may "jump" over combinators when moving to the end of the selector // -// This is a backwards-compat quirk of :before and :after variants. +// This is a backwards-compat quirk of pseudo element variants from earlier versions of Tailwind CSS. /** @typedef {'terminal' | 'actionable' | 'jumpable'} PseudoProperty */ /** @type {Record} */ let elementProperties = { + // Pseudo elements from the spec '::after': ['terminal', 'jumpable'], - '::backdrop': ['terminal'], + '::backdrop': ['terminal', 'jumpable'], '::before': ['terminal', 'jumpable'], '::cue': ['terminal'], '::cue-region': ['terminal'], '::first-letter': ['terminal', 'jumpable'], '::first-line': ['terminal', 'jumpable'], '::grammar-error': ['terminal'], - '::marker': ['terminal'], + '::marker': ['terminal', 'jumpable'], '::part': ['terminal', 'actionable'], - '::placeholder': ['terminal'], - '::selection': ['terminal'], + '::placeholder': ['terminal', 'jumpable'], + '::selection': ['terminal', 'jumpable'], '::slotted': ['terminal'], '::spelling-error': ['terminal'], '::target-text': ['terminal'], - // other + // Pseudo elements from the spec with special rules '::file-selector-button': ['terminal', 'actionable'], - '::-webkit-progress-bar': ['terminal', 'actionable'], - // Webkit scroll bar pseudo elements can be combined with user-action pseudo classes - '::-webkit-scrollbar': ['terminal', 'actionable'], - '::-webkit-scrollbar-button': ['terminal', 'actionable'], - '::-webkit-scrollbar-thumb': ['terminal', 'actionable'], - '::-webkit-scrollbar-track': ['terminal', 'actionable'], - '::-webkit-scrollbar-track-piece': ['terminal', 'actionable'], - '::-webkit-scrollbar-corner': ['terminal', 'actionable'], - '::-webkit-resizer': ['terminal', 'actionable'], + // Library-specific pseudo elements used by component libraries + // These are Shadow DOM-like + '::deep': ['actionable'], + '::v-deep': ['actionable'], + '::ng-deep': ['actionable'], // Note: As a rule, double colons (::) should be used instead of a single colon // (:). This distinguishes pseudo-classes from pseudo-elements. However, since @@ -65,8 +62,8 @@ let elementProperties = { // The default value is used when the pseudo-element is not recognized // Because it's not recognized, we don't know if it's terminal or not - // So we assume it can't be moved AND can have user-action pseudo classes attached to it - __default__: ['actionable'], + // So we assume it can be moved AND can have user-action pseudo classes attached to it + __default__: ['terminal', 'actionable'], } /** diff --git a/src/util/validateConfig.js b/src/util/validateConfig.js index 8c22e4450..ebd63d2d2 100644 --- a/src/util/validateConfig.js +++ b/src/util/validateConfig.js @@ -1,3 +1,4 @@ +import pc from 'picocolors' import log from './log' export function validateConfig(config) { @@ -9,6 +10,15 @@ export function validateConfig(config) { ]) } + if (config.content.files.includes('auto')) { + log.group('auto-content-experimental', (log) => { + log.info([pc.bold('Automatically detecting Tailwind CSS content sources...')]) + log.warn([ + 'Automatic content detection is experimental, and the behavior may change at any time.', + ]) + }) + } + // Warn if the line-clamp plugin is installed try { let plugin = require('@tailwindcss/line-clamp') diff --git a/src/value-parser/LICENSE b/src/value-parser/LICENSE new file mode 100644 index 000000000..6dcaefcbe --- /dev/null +++ b/src/value-parser/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) Bogdan Chadkin + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/value-parser/README.md b/src/value-parser/README.md new file mode 100644 index 000000000..ea9e20291 --- /dev/null +++ b/src/value-parser/README.md @@ -0,0 +1,3 @@ +# postcss-value-parser (forked + inlined) + +This is a customized version of of [PostCSS Value Parser](https://github.com/TrySound/postcss-value-parser) to fix some bugs around parsing CSS functions. diff --git a/src/value-parser/index.d.ts b/src/value-parser/index.d.ts new file mode 100644 index 000000000..0c0c4b991 --- /dev/null +++ b/src/value-parser/index.d.ts @@ -0,0 +1,177 @@ +declare namespace postcssValueParser { + interface BaseNode { + /** + * The offset, inclusive, inside the CSS value at which the node starts. + */ + sourceIndex: number + + /** + * The offset, exclusive, inside the CSS value at which the node ends. + */ + sourceEndIndex: number + + /** + * The node's characteristic value + */ + value: string + } + + interface ClosableNode { + /** + * Whether the parsed CSS value ended before the node was properly closed + */ + unclosed?: true + } + + interface AdjacentAwareNode { + /** + * The token at the start of the node + */ + before: string + + /** + * The token at the end of the node + */ + after: string + } + + interface CommentNode extends BaseNode, ClosableNode { + type: 'comment' + } + + interface DivNode extends BaseNode, AdjacentAwareNode { + type: 'div' + } + + interface FunctionNode extends BaseNode, ClosableNode, AdjacentAwareNode { + type: 'function' + + /** + * Nodes inside the function + */ + nodes: Node[] + } + + interface SpaceNode extends BaseNode { + type: 'space' + } + + interface StringNode extends BaseNode, ClosableNode { + type: 'string' + + /** + * The quote type delimiting the string + */ + quote: '"' | "'" + } + + interface UnicodeRangeNode extends BaseNode { + type: 'unicode-range' + } + + interface WordNode extends BaseNode { + type: 'word' + } + + /** + * Any node parsed from a CSS value + */ + type Node = + | CommentNode + | DivNode + | FunctionNode + | SpaceNode + | StringNode + | UnicodeRangeNode + | WordNode + + interface CustomStringifierCallback { + /** + * @param node The node to stringify + * @returns The serialized CSS representation of the node + */ + (nodes: Node): string | undefined + } + + interface WalkCallback { + /** + * @param node The currently visited node + * @param index The index of the node in the series of parsed nodes + * @param nodes The series of parsed nodes + * @returns Returning `false` will prevent traversal of descendant nodes (only applies if `bubble` was set to `true` in the `walk()` call) + */ + (node: Node, index: number, nodes: Node[]): void | boolean + } + + /** + * A CSS dimension, decomposed into its numeric and unit parts + */ + interface Dimension { + number: string + unit: string + } + + /** + * A wrapper around a parsed CSS value that allows for inspecting and walking nodes + */ + interface ParsedValue { + /** + * The series of parsed nodes + */ + nodes: Node[] + + /** + * Walk all parsed nodes, applying a callback + * + * @param callback A visitor callback that will be executed for each node + * @param bubble When set to `true`, walking will be done inside-out instead of outside-in + */ + walk(callback: WalkCallback, bubble?: boolean): this + } + + interface ValueParser { + /** + * Decompose a CSS dimension into its numeric and unit part + * + * @param value The dimension to decompose + * @returns An object representing `number` and `unit` part of the dimension or `false` if the decomposing fails + */ + unit(value: string): Dimension | false + + /** + * Serialize a series of nodes into a CSS value + * + * @param nodes The nodes to stringify + * @param custom A custom stringifier callback + * @returns The generated CSS value + */ + stringify(nodes: Node | Node[], custom?: CustomStringifierCallback): string + + /** + * Walk a series of nodes, applying a callback + * + * @param nodes The nodes to walk + * @param callback A visitor callback that will be executed for each node + * @param bubble When set to `true`, walking will be done inside-out instead of outside-in + */ + walk(nodes: Node[], callback: WalkCallback, bubble?: boolean): void + + /** + * Parse a CSS value into a series of nodes to operate on + * + * @param value The value to parse + */ + new (value: string): ParsedValue + + /** + * Parse a CSS value into a series of nodes to operate on + * + * @param value The value to parse + */ + (value: string): ParsedValue + } +} + +declare const postcssValueParser: postcssValueParser.ValueParser + +export = postcssValueParser diff --git a/src/value-parser/index.js b/src/value-parser/index.js new file mode 100644 index 000000000..5587ccfa3 --- /dev/null +++ b/src/value-parser/index.js @@ -0,0 +1,28 @@ +var parse = require('./parse') +var walk = require('./walk') +var stringify = require('./stringify') + +function ValueParser(value) { + if (this instanceof ValueParser) { + this.nodes = parse(value) + return this + } + return new ValueParser(value) +} + +ValueParser.prototype.toString = function () { + return Array.isArray(this.nodes) ? stringify(this.nodes) : '' +} + +ValueParser.prototype.walk = function (cb, bubble) { + walk(this.nodes, cb, bubble) + return this +} + +ValueParser.unit = require('./unit') + +ValueParser.walk = walk + +ValueParser.stringify = stringify + +module.exports = ValueParser diff --git a/src/value-parser/parse.js b/src/value-parser/parse.js new file mode 100644 index 000000000..445599664 --- /dev/null +++ b/src/value-parser/parse.js @@ -0,0 +1,303 @@ +var openParentheses = '('.charCodeAt(0) +var closeParentheses = ')'.charCodeAt(0) +var singleQuote = "'".charCodeAt(0) +var doubleQuote = '"'.charCodeAt(0) +var backslash = '\\'.charCodeAt(0) +var slash = '/'.charCodeAt(0) +var comma = ','.charCodeAt(0) +var colon = ':'.charCodeAt(0) +var star = '*'.charCodeAt(0) +var uLower = 'u'.charCodeAt(0) +var uUpper = 'U'.charCodeAt(0) +var plus = '+'.charCodeAt(0) +var isUnicodeRange = /^[a-f0-9?-]+$/i + +module.exports = function (input) { + var tokens = [] + var value = input + + var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos + var pos = 0 + var code = value.charCodeAt(pos) + var max = value.length + var stack = [{ nodes: tokens }] + var balanced = 0 + var parent + + var name = '' + var before = '' + var after = '' + + while (pos < max) { + // Whitespaces + if (code <= 32) { + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + token = value.slice(pos, next) + + prev = tokens[tokens.length - 1] + if (code === closeParentheses && balanced) { + after = token + } else if (prev && prev.type === 'div') { + prev.after = token + prev.sourceEndIndex += token.length + } else if ( + code === comma || + code === colon || + (code === slash && + value.charCodeAt(next + 1) !== star && + (!parent || (parent && parent.type === 'function' && false))) + ) { + before = token + } else { + tokens.push({ + type: 'space', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + + // Quotes + } else if (code === singleQuote || code === doubleQuote) { + next = pos + quote = code === singleQuote ? "'" : '"' + token = { + type: 'string', + sourceIndex: pos, + quote: quote, + } + do { + escape = false + next = value.indexOf(quote, next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += quote + next = value.length - 1 + token.unclosed = true + } + } while (escape) + token.value = value.slice(pos + 1, next) + token.sourceEndIndex = token.unclosed ? next : next + 1 + tokens.push(token) + pos = next + 1 + code = value.charCodeAt(pos) + + // Comments + } else if (code === slash && value.charCodeAt(pos + 1) === star) { + next = value.indexOf('*/', pos) + + token = { + type: 'comment', + sourceIndex: pos, + sourceEndIndex: next + 2, + } + + if (next === -1) { + token.unclosed = true + next = value.length + token.sourceEndIndex = next + } + + token.value = value.slice(pos + 2, next) + tokens.push(token) + + pos = next + 2 + code = value.charCodeAt(pos) + + // Operation within calc + } else if ((code === slash || code === star) && parent && parent.type === 'function' && true) { + token = value[pos] + tokens.push({ + type: 'word', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + }) + pos += 1 + code = value.charCodeAt(pos) + + // Dividers + } else if (code === slash || code === comma || code === colon) { + token = value[pos] + + tokens.push({ + type: 'div', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + before: before, + after: '', + }) + before = '' + + pos += 1 + code = value.charCodeAt(pos) + + // Open parentheses + } else if (openParentheses === code) { + // Whitespaces after open parentheses + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + parenthesesOpenPos = pos + token = { + type: 'function', + sourceIndex: pos - name.length, + value: name, + before: value.slice(parenthesesOpenPos + 1, next), + } + pos = next + + if (name === 'url' && code !== singleQuote && code !== doubleQuote) { + next -= 1 + do { + escape = false + next = value.indexOf(')', next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += ')' + next = value.length - 1 + token.unclosed = true + } + } while (escape) + // Whitespaces before closed + whitespacePos = next + do { + whitespacePos -= 1 + code = value.charCodeAt(whitespacePos) + } while (code <= 32) + if (parenthesesOpenPos < whitespacePos) { + if (pos !== whitespacePos + 1) { + token.nodes = [ + { + type: 'word', + sourceIndex: pos, + sourceEndIndex: whitespacePos + 1, + value: value.slice(pos, whitespacePos + 1), + }, + ] + } else { + token.nodes = [] + } + if (token.unclosed && whitespacePos + 1 !== next) { + token.after = '' + token.nodes.push({ + type: 'space', + sourceIndex: whitespacePos + 1, + sourceEndIndex: next, + value: value.slice(whitespacePos + 1, next), + }) + } else { + token.after = value.slice(whitespacePos + 1, next) + token.sourceEndIndex = next + } + } else { + token.after = '' + token.nodes = [] + } + pos = next + 1 + token.sourceEndIndex = token.unclosed ? next : pos + code = value.charCodeAt(pos) + tokens.push(token) + } else { + balanced += 1 + token.after = '' + token.sourceEndIndex = pos + 1 + tokens.push(token) + stack.push(token) + tokens = token.nodes = [] + parent = token + } + name = '' + + // Close parentheses + } else if (closeParentheses === code && balanced) { + pos += 1 + code = value.charCodeAt(pos) + + parent.after = after + parent.sourceEndIndex += after.length + after = '' + balanced -= 1 + stack[stack.length - 1].sourceEndIndex = pos + stack.pop() + parent = stack[balanced] + tokens = parent.nodes + + // Words + } else { + next = pos + do { + if (code === backslash) { + next += 1 + } + next += 1 + code = value.charCodeAt(next) + } while ( + next < max && + !( + code <= 32 || + code === singleQuote || + code === doubleQuote || + code === comma || + code === colon || + code === slash || + code === openParentheses || + (code === star && parent && parent.type === 'function' && true) || + (code === slash && parent.type === 'function' && true) || + (code === closeParentheses && balanced) + ) + ) + token = value.slice(pos, next) + + if (openParentheses === code) { + name = token + } else if ( + (uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) && + plus === token.charCodeAt(1) && + isUnicodeRange.test(token.slice(2)) + ) { + tokens.push({ + type: 'unicode-range', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } else { + tokens.push({ + type: 'word', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + } + } + + for (pos = stack.length - 1; pos; pos -= 1) { + stack[pos].unclosed = true + stack[pos].sourceEndIndex = value.length + } + + return stack[0].nodes +} diff --git a/src/value-parser/stringify.js b/src/value-parser/stringify.js new file mode 100644 index 000000000..c95890610 --- /dev/null +++ b/src/value-parser/stringify.js @@ -0,0 +1,41 @@ +function stringifyNode(node, custom) { + var type = node.type + var value = node.value + var buf + var customResult + + if (custom && (customResult = custom(node)) !== undefined) { + return customResult + } else if (type === 'word' || type === 'space') { + return value + } else if (type === 'string') { + buf = node.quote || '' + return buf + value + (node.unclosed ? '' : buf) + } else if (type === 'comment') { + return '/*' + value + (node.unclosed ? '' : '*/') + } else if (type === 'div') { + return (node.before || '') + value + (node.after || '') + } else if (Array.isArray(node.nodes)) { + buf = stringify(node.nodes, custom) + if (type !== 'function') { + return buf + } + return value + '(' + (node.before || '') + buf + (node.after || '') + (node.unclosed ? '' : ')') + } + return value +} + +function stringify(nodes, custom) { + var result, i + + if (Array.isArray(nodes)) { + result = '' + for (i = nodes.length - 1; ~i; i -= 1) { + result = stringifyNode(nodes[i], custom) + result + } + return result + } + return stringifyNode(nodes, custom) +} + +module.exports = stringify diff --git a/src/value-parser/unit.js b/src/value-parser/unit.js new file mode 100644 index 000000000..42d6cd3a7 --- /dev/null +++ b/src/value-parser/unit.js @@ -0,0 +1,118 @@ +var minus = '-'.charCodeAt(0) +var plus = '+'.charCodeAt(0) +var dot = '.'.charCodeAt(0) +var exp = 'e'.charCodeAt(0) +var EXP = 'E'.charCodeAt(0) + +// Check if three code points would start a number +// https://www.w3.org/TR/css-syntax-3/#starts-with-a-number +function likeNumber(value) { + var code = value.charCodeAt(0) + var nextCode + + if (code === plus || code === minus) { + nextCode = value.charCodeAt(1) + + if (nextCode >= 48 && nextCode <= 57) { + return true + } + + var nextNextCode = value.charCodeAt(2) + + if (nextCode === dot && nextNextCode >= 48 && nextNextCode <= 57) { + return true + } + + return false + } + + if (code === dot) { + nextCode = value.charCodeAt(1) + + if (nextCode >= 48 && nextCode <= 57) { + return true + } + + return false + } + + if (code >= 48 && code <= 57) { + return true + } + + return false +} + +// Consume a number +// https://www.w3.org/TR/css-syntax-3/#consume-number +module.exports = function (value) { + var pos = 0 + var length = value.length + var code + var nextCode + var nextNextCode + + if (length === 0 || !likeNumber(value)) { + return false + } + + code = value.charCodeAt(pos) + + if (code === plus || code === minus) { + pos++ + } + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + + code = value.charCodeAt(pos) + nextCode = value.charCodeAt(pos + 1) + + if (code === dot && nextCode >= 48 && nextCode <= 57) { + pos += 2 + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + } + + code = value.charCodeAt(pos) + nextCode = value.charCodeAt(pos + 1) + nextNextCode = value.charCodeAt(pos + 2) + + if ( + (code === exp || code === EXP) && + ((nextCode >= 48 && nextCode <= 57) || + ((nextCode === plus || nextCode === minus) && nextNextCode >= 48 && nextNextCode <= 57)) + ) { + pos += nextCode === plus || nextCode === minus ? 3 : 2 + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + } + + return { + number: value.slice(0, pos), + unit: value.slice(pos), + } +} diff --git a/src/value-parser/walk.js b/src/value-parser/walk.js new file mode 100644 index 000000000..dd20a4392 --- /dev/null +++ b/src/value-parser/walk.js @@ -0,0 +1,18 @@ +module.exports = function walk(nodes, cb, bubble) { + var i, max, node, result + + for (i = 0, max = nodes.length; i < max; i += 1) { + node = nodes[i] + if (!bubble) { + result = cb(node, i, nodes) + } + + if (result !== false && node.type === 'function' && Array.isArray(node.nodes)) { + walk(node.nodes, cb, bubble) + } + + if (bubble) { + cb(node, i, nodes) + } + } +} diff --git a/stubs/config.full.js b/stubs/config.full.js index c32ccd3a0..bda7d03ba 100644 --- a/stubs/config.full.js +++ b/stubs/config.full.js @@ -1,5 +1,5 @@ module.exports = { - content: [], + content: ['auto'], presets: [], darkMode: 'media', // or 'class' theme: { @@ -15,6 +15,7 @@ module.exports = { bounce: 'bounce 1s infinite', }, aria: { + busy: 'busy="true"', checked: 'checked="true"', disabled: 'disabled="true"', expanded: 'expanded="true"', @@ -516,6 +517,9 @@ module.exports = { '5/6': '83.333333%', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -620,6 +624,9 @@ module.exports = { none: 'none', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -649,6 +656,9 @@ module.exports = { 0: '0px', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -966,6 +976,9 @@ module.exports = { '11/12': '91.666667%', full: '100%', screen: '100vw', + svw: '100svw', + lvw: '100lvw', + dvw: '100dvw', min: 'min-content', max: 'max-content', fit: 'fit-content', diff --git a/stubs/config.simple.js b/stubs/config.simple.js index 9843c0557..3e0d35604 100644 --- a/stubs/config.simple.js +++ b/stubs/config.simple.js @@ -1,5 +1,5 @@ module.exports = { - content: [], + content: ['auto'], theme: { extend: {}, }, diff --git a/stubs/postcss.config.cjs b/stubs/postcss.config.cjs index 33ad091d2..08a01d4d1 100644 --- a/stubs/postcss.config.cjs +++ b/stubs/postcss.config.cjs @@ -1,6 +1,5 @@ module.exports = { plugins: { tailwindcss: {}, - autoprefixer: {}, }, } diff --git a/stubs/postcss.config.js b/stubs/postcss.config.js index 2e7af2b7f..284180207 100644 --- a/stubs/postcss.config.js +++ b/stubs/postcss.config.js @@ -1,6 +1,5 @@ export default { plugins: { tailwindcss: {}, - autoprefixer: {}, }, } diff --git a/tests/animations.test.js b/tests/animations.test.js index 958f24252..dd05c6eba 100644 --- a/tests/animations.test.js +++ b/tests/animations.test.js @@ -1,278 +1,279 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .animate-spin { - animation: 1s linear infinite spin; - } - @keyframes ping { - 75%, - 100% { - opacity: 0; - transform: scale(2); - } - } - .hover\:animate-ping:hover { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; - } - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } - } - .group:hover .group-hover\:animate-bounce { - animation: 1s infinite bounce; - } - `) - }) - }) - - test('custom', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - }, - animation: { - one: 'one 2s', - }, - }, +test('basic', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, }, - } + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes one { - to { - transform: rotate(360deg); - } + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes spin { + to { + transform: rotate(360deg); } - .animate-one { - animation: 2s one; + } + .animate-spin { + animation: 1s linear infinite spin; + } + @keyframes ping { + 75%, + 100% { + opacity: 0; + transform: scale(2); } - `) - }) - }) - - test('custom prefixed', () => { - let config = { - prefix: 'tw-', - content: [{ raw: `
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - }, - animation: { - one: 'one 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes tw-one { - to { - transform: rotate(360deg); - } + } + .hover\:animate-ping:hover { + animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; + } + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); } - .tw-animate-one { - animation: 2s tw-one; + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; } - `) - }) - }) - - test('multiple', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - animation: { - multiple: 'bounce 2s linear, pulse 3s ease-in', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .animate-multiple { - animation: 2s linear bounce, 3s ease-in pulse; - } - `) - }) - }) - - test('multiple custom', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - two: { to: { transform: 'scale(1.23)' } }, - }, - animation: { - multiple: 'one 2s, two 3s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes one { - to { - transform: rotate(360deg); - } - } - @keyframes two { - to { - transform: scale(1.23); - } - } - .animate-multiple { - animation: 2s one, 3s two; - } - `) - }) - }) - - test('with dots in the name', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - theme: { - extend: { - keyframes: { - 'zoom-.5': { to: { transform: 'scale(0.5)' } }, - 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, - }, - animation: { - 'zoom-.5': 'zoom-.5 2s', - 'zoom-1.5': 'zoom-1.5 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes zoom-\.5 { - to { - transform: scale(0.5); - } - } - .animate-zoom-\.5 { - animation: 2s zoom-\.5; - } - @keyframes zoom-1\.5 { - to { - transform: scale(1.5); - } - } - .animate-zoom-1\.5 { - animation: 2s zoom-1\.5; - } - `) - }) - }) - - test('with dots in the name and prefix', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
-
- `, - }, - ], - theme: { - extend: { - keyframes: { - 'zoom-.5': { to: { transform: 'scale(0.5)' } }, - 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, - }, - animation: { - 'zoom-.5': 'zoom-.5 2s', - 'zoom-1.5': 'zoom-1.5 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes tw-zoom-\.5 { - to { - transform: scale(0.5); - } - } - .tw-animate-zoom-\.5 { - animation: 2s tw-zoom-\.5; - } - @keyframes tw-zoom-1\.5 { - to { - transform: scale(1.5); - } - } - .tw-animate-zoom-1\.5 { - animation: 2s tw-zoom-1\.5; - } - `) - }) + } + .group:hover .group-hover\:animate-bounce { + animation: 1s infinite bounce; + } + `) + }) +}) + +test('custom', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + }, + animation: { + one: 'one 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes one { + to { + transform: rotate(360deg); + } + } + .animate-one { + animation: 2s one; + } + `) + }) +}) + +test('custom prefixed', () => { + let config = { + prefix: 'tw-', + content: [{ raw: `
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + }, + animation: { + one: 'one 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes tw-one { + to { + transform: rotate(360deg); + } + } + .tw-animate-one { + animation: 2s tw-one; + } + `) + }) +}) + +test('multiple', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + animation: { + multiple: 'bounce 2s linear, pulse 3s ease-in', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); + } + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; + } + } + @keyframes pulse { + 50% { + opacity: 0.5; + } + } + .animate-multiple { + animation: 2s linear bounce, 3s ease-in pulse; + } + `) + }) +}) + +test('multiple custom', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + two: { to: { transform: 'scale(1.23)' } }, + }, + animation: { + multiple: 'one 2s, two 3s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes one { + to { + transform: rotate(360deg); + } + } + @keyframes two { + to { + transform: scale(1.23); + } + } + .animate-multiple { + animation: 2s one, 3s two; + } + `) + }) +}) + +test('with dots in the name', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-0.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-0.5': 'zoom-0.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes zoom-0\.5 { + to { + transform: scale(0.5); + } + } + + .animate-zoom-0\.5 { + animation: 2s zoom-0\.5; + } + + @keyframes zoom-1\.5 { + to { + transform: scale(1.5); + } + } + + .animate-zoom-1\.5 { + animation: 2s zoom-1\.5; + } + `) + }) +}) + +test('with dots in the name and prefix', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-.5': 'zoom-.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes tw-zoom-\.5 { + to { + transform: scale(0.5); + } + } + .tw-animate-zoom-\.5 { + animation: 2s tw-zoom-\.5; + } + @keyframes tw-zoom-1\.5 { + to { + transform: scale(1.5); + } + } + .tw-animate-zoom-1\.5 { + animation: 2s tw-zoom-1\.5; + } + `) }) }) diff --git a/tests/any-type.test.js b/tests/any-type.test.js index 7b7873966..c9cce9c7a 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -1,1307 +1,797 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - // Hi there, so you are debugging this test because something failed... right? Well we can look into - // the future and guessed that this would happen. So basically it means that we (it was probably - // you, silly) introduced a new plugin that conflicts with an existing plugin that has (either - // implicit or explicit) an `any` type. - // - // Now it is your job to decide which one should win, and mark that one with - // ```diff - // - 'any' - // + ['any', { preferOnConflict: true }] - // ``` - // in the corePlugins.js file. - // - // You probably want to let the original one win for backwards compatible reasons. - // - // Good luck! - test('any types are set on correct plugins', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +// Hi there, so you are debugging this test because something failed... right? Well we can look into +// the future and guessed that this would happen. So basically it means that we (it was probably +// you, silly) introduced a new plugin that conflicts with an existing plugin that has (either +// implicit or explicit) an `any` type. +// +// Now it is your job to decide which one should win, and mark that one with +// ```diff +// - 'any' +// + ['any', { preferOnConflict: true }] +// ``` +// in the corePlugins.js file. +// +// You probably want to let the original one win for backwards compatible reasons. +// +// Good luck! +test('any types are set on correct plugins', () => { + let config = { + future: { + logicalSiblingUtilities: false, + disableColorOpacityUtilitiesByDefault: false, + }, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - oxide.expect(result.css).toMatchFormattedCss(css` - .inset-\[var\(--any-value\)\] { - inset: var(--any-value); - } - .inset-x-\[var\(--any-value\)\] { - left: var(--any-value); - right: var(--any-value); - } - .inset-y-\[var\(--any-value\)\] { - top: var(--any-value); - bottom: var(--any-value); - } - .bottom-\[var\(--any-value\)\] { - bottom: var(--any-value); - } - .left-\[var\(--any-value\)\] { - left: var(--any-value); - } - .right-\[var\(--any-value\)\] { - right: var(--any-value); - } - .top-\[var\(--any-value\)\] { - top: var(--any-value); - } - .z-\[var\(--any-value\)\] { - z-index: var(--any-value); - } - .order-\[var\(--any-value\)\] { - order: var(--any-value); - } - .col-\[var\(--any-value\)\] { - grid-column: var(--any-value); - } - .col-start-\[var\(--any-value\)\] { - grid-column-start: var(--any-value); - } - .col-end-\[var\(--any-value\)\] { - grid-column-end: var(--any-value); - } - .row-\[var\(--any-value\)\] { - grid-row: var(--any-value); - } - .row-start-\[var\(--any-value\)\] { - grid-row-start: var(--any-value); - } - .row-end-\[var\(--any-value\)\] { - grid-row-end: var(--any-value); - } - .m-\[var\(--any-value\)\] { - margin: var(--any-value); - } - .mx-\[var\(--any-value\)\] { - margin-left: var(--any-value); - margin-right: var(--any-value); - } - .my-\[var\(--any-value\)\] { - margin-top: var(--any-value); - margin-bottom: var(--any-value); - } - .mb-\[var\(--any-value\)\] { - margin-bottom: var(--any-value); - } - .ml-\[var\(--any-value\)\] { - margin-left: var(--any-value); - } - .mr-\[var\(--any-value\)\] { - margin-right: var(--any-value); - } - .mt-\[var\(--any-value\)\] { - margin-top: var(--any-value); - } - .aspect-\[var\(--any-value\)\] { - aspect-ratio: var(--any-value); - } - .h-\[var\(--any-value\)\] { - height: var(--any-value); - } - .max-h-\[var\(--any-value\)\] { - max-height: var(--any-value); - } - .min-h-\[var\(--any-value\)\] { - min-height: var(--any-value); - } - .w-\[var\(--any-value\)\] { - width: var(--any-value); - } - .min-w-\[var\(--any-value\)\] { - min-width: var(--any-value); - } - .max-w-\[var\(--any-value\)\] { - max-width: var(--any-value); - } - .flex-\[var\(--any-value\)\] { - flex: var(--any-value); - } - .flex-shrink-\[var\(--any-value\)\], - .shrink-\[var\(--any-value\)\] { - flex-shrink: var(--any-value); - } - .flex-grow-\[var\(--any-value\)\], - .grow-\[var\(--any-value\)\] { - flex-grow: var(--any-value); - } - .basis-\[var\(--any-value\)\] { - flex-basis: var(--any-value); - } - .border-spacing-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-x-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-y-\[var\(--any-value\)\] { - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .origin-\[var\(--any-value\)\] { - transform-origin: var(--any-value); - } - .translate-x-\[var\(--any-value\)\] { - --tw-translate-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .translate-y-\[var\(--any-value\)\] { - --tw-translate-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .rotate-\[var\(--any-value\)\] { - --tw-rotate: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-y-\[var\(--any-value\)\] { - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .animate-\[var\(--any-value\)\] { - animation: var(--any-value); - } - .cursor-\[var\(--any-value\)\] { - cursor: var(--any-value); - } - .scroll-m-\[var\(--any-value\)\] { - scroll-margin: var(--any-value); - } - .scroll-mx-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - scroll-margin-right: var(--any-value); - } - .scroll-my-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - scroll-margin-bottom: var(--any-value); - } - .scroll-mb-\[var\(--any-value\)\] { - scroll-margin-bottom: var(--any-value); - } - .scroll-ml-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - } - .scroll-mr-\[var\(--any-value\)\] { - scroll-margin-right: var(--any-value); - } - .scroll-mt-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - } - .scroll-p-\[var\(--any-value\)\] { - scroll-padding: var(--any-value); - } - .scroll-px-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - scroll-padding-right: var(--any-value); - } - .scroll-py-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - scroll-padding-bottom: var(--any-value); - } - .scroll-pb-\[var\(--any-value\)\] { - scroll-padding-bottom: var(--any-value); - } - .scroll-pl-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - } - .scroll-pr-\[var\(--any-value\)\] { - scroll-padding-right: var(--any-value); - } - .scroll-pt-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - } - .list-\[var\(--any-value\)\] { - list-style-type: var(--any-value); - } - .columns-\[var\(--any-value\)\] { - columns: var(--any-value); - } - .auto-cols-\[var\(--any-value\)\] { - grid-auto-columns: var(--any-value); - } - .auto-rows-\[var\(--any-value\)\] { - grid-auto-rows: var(--any-value); - } - .grid-cols-\[var\(--any-value\)\] { - grid-template-columns: var(--any-value); - } - .grid-rows-\[var\(--any-value\)\] { - grid-template-rows: var(--any-value); - } - .gap-\[var\(--any-value\)\] { - gap: var(--any-value); - } - .gap-x-\[var\(--any-value\)\] { - column-gap: var(--any-value); - } - .gap-y-\[var\(--any-value\)\] { - row-gap: var(--any-value); - } - .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(var(--any-value) * var(--tw-space-x-reverse)); - } - .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); - } - .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); - } - .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--any-value); - } - .rounded-\[var\(--any-value\)\] { - border-radius: var(--any-value); - } - .rounded-b-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-l-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-r-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - border-bottom-right-radius: var(--any-value); - } - .rounded-t-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-top-right-radius: var(--any-value); - } - .rounded-bl-\[var\(--any-value\)\] { - border-bottom-left-radius: var(--any-value); - } - .rounded-br-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - } - .rounded-tl-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - } - .rounded-tr-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - } - .border-\[var\(--any-value\)\] { - border-color: var(--any-value); - } - .border-x-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - border-right-color: var(--any-value); - } - .border-y-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - border-bottom-color: var(--any-value); - } - .border-b-\[var\(--any-value\)\] { - border-bottom-color: var(--any-value); - } - .border-l-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - } - .border-r-\[var\(--any-value\)\] { - border-right-color: var(--any-value); - } - .border-t-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - } - .bg-\[var\(--any-value\)\] { - background-color: var(--any-value); - } - .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); - } - .fill-\[var\(--any-value\)\] { - fill: var(--any-value); - } - .stroke-\[var\(--any-value\)\] { - stroke: var(--any-value); - } - .object-\[var\(--any-value\)\] { - object-position: var(--any-value); - } - .p-\[var\(--any-value\)\] { - padding: var(--any-value); - } - .px-\[var\(--any-value\)\] { - padding-left: var(--any-value); - padding-right: var(--any-value); - } - .py-\[var\(--any-value\)\] { - padding-top: var(--any-value); - padding-bottom: var(--any-value); - } - .pb-\[var\(--any-value\)\] { - padding-bottom: var(--any-value); - } - .pl-\[var\(--any-value\)\] { - padding-left: var(--any-value); - } - .pr-\[var\(--any-value\)\] { - padding-right: var(--any-value); - } - .pt-\[var\(--any-value\)\] { - padding-top: var(--any-value); - } - .indent-\[var\(--any-value\)\] { - text-indent: var(--any-value); - } - .align-\[var\(--any-value\)\] { - vertical-align: var(--any-value); - } - .font-\[var\(--any-value\)\] { - font-weight: var(--any-value); - } - .leading-\[var\(--any-value\)\] { - line-height: var(--any-value); - } - .tracking-\[var\(--any-value\)\] { - letter-spacing: var(--any-value); - } - .text-\[var\(--any-value\)\] { - color: var(--any-value); - } - .decoration-\[var\(--any-value\)\] { - text-decoration-color: var(--any-value); - } - .underline-offset-\[var\(--any-value\)\] { - text-underline-offset: var(--any-value); - } - .placeholder-\[var\(--any-value\)\]::placeholder { - color: var(--any-value); - } - .caret-\[var\(--any-value\)\] { - caret-color: var(--any-value); - } - .accent-\[var\(--any-value\)\] { - accent-color: var(--any-value); - } - .opacity-\[var\(--any-value\)\] { - opacity: var(--any-value); - } - .shadow-\[var\(--any-value\)\] { - --tw-shadow-color: var(--any-value); - --tw-shadow: var(--tw-shadow-colored); - } - .outline-offset-\[var\(--any-value\)\] { - outline-offset: var(--any-value); - } - .outline-\[var\(--any-value\)\] { - outline-color: var(--any-value); - } - .ring-\[var\(--any-value\)\] { - --tw-ring-color: var(--any-value); - } - .ring-offset-\[var\(--any-value\)\] { - --tw-ring-offset-color: var(--any-value); - } - .blur-\[var\(--any-value\)\] { - --tw-blur: blur(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .brightness-\[var\(--any-value\)\] { - --tw-brightness: brightness(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .contrast-\[var\(--any-value\)\] { - --tw-contrast: contrast(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .drop-shadow-\[var\(--any-value\)\] { - --tw-drop-shadow: drop-shadow(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .grayscale-\[var\(--any-value\)\] { - --tw-grayscale: grayscale(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .hue-rotate-\[var\(--any-value\)\] { - --tw-hue-rotate: hue-rotate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .invert-\[var\(--any-value\)\] { - --tw-invert: invert(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .saturate-\[var\(--any-value\)\] { - --tw-saturate: saturate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .sepia-\[var\(--any-value\)\] { - --tw-sepia: sepia(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .backdrop-blur-\[var\(--any-value\)\] { - --tw-backdrop-blur: blur(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-brightness-\[var\(--any-value\)\] { - --tw-backdrop-brightness: brightness(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-contrast-\[var\(--any-value\)\] { - --tw-backdrop-contrast: contrast(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-grayscale-\[var\(--any-value\)\] { - --tw-backdrop-grayscale: grayscale(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-hue-rotate-\[var\(--any-value\)\] { - --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-invert-\[var\(--any-value\)\] { - --tw-backdrop-invert: invert(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-opacity-\[var\(--any-value\)\] { - --tw-backdrop-opacity: opacity(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-saturate-\[var\(--any-value\)\] { - --tw-backdrop-saturate: saturate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-sepia-\[var\(--any-value\)\] { - --tw-backdrop-sepia: sepia(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .transition-\[var\(--any-value\)\] { - transition-property: var(--any-value); - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .delay-\[var\(--any-value\)\] { - transition-delay: var(--any-value); - } - .duration-\[var\(--any-value\)\] { - transition-duration: var(--any-value); - } - .ease-\[var\(--any-value\)\] { - transition-timing-function: var(--any-value); - } - .will-change-\[var\(--any-value\)\] { - will-change: var(--any-value); - } - .content-\[var\(--any-value\)\] { - --tw-content: var(--any-value); - content: var(--tw-content); - } - `) - stable.expect(result.css).toMatchFormattedCss(css` - .inset-\[var\(--any-value\)\] { - inset: var(--any-value); - } - .inset-x-\[var\(--any-value\)\] { - left: var(--any-value); - right: var(--any-value); - } - .inset-y-\[var\(--any-value\)\] { - top: var(--any-value); - bottom: var(--any-value); - } - .bottom-\[var\(--any-value\)\] { - bottom: var(--any-value); - } - .left-\[var\(--any-value\)\] { - left: var(--any-value); - } - .right-\[var\(--any-value\)\] { - right: var(--any-value); - } - .top-\[var\(--any-value\)\] { - top: var(--any-value); - } - .z-\[var\(--any-value\)\] { - z-index: var(--any-value); - } - .order-\[var\(--any-value\)\] { - order: var(--any-value); - } - .col-\[var\(--any-value\)\] { - grid-column: var(--any-value); - } - .col-start-\[var\(--any-value\)\] { - grid-column-start: var(--any-value); - } - .col-end-\[var\(--any-value\)\] { - grid-column-end: var(--any-value); - } - .row-\[var\(--any-value\)\] { - grid-row: var(--any-value); - } - .row-start-\[var\(--any-value\)\] { - grid-row-start: var(--any-value); - } - .row-end-\[var\(--any-value\)\] { - grid-row-end: var(--any-value); - } - .m-\[var\(--any-value\)\] { - margin: var(--any-value); - } - .mx-\[var\(--any-value\)\] { - margin-left: var(--any-value); - margin-right: var(--any-value); - } - .my-\[var\(--any-value\)\] { - margin-top: var(--any-value); - margin-bottom: var(--any-value); - } - .mb-\[var\(--any-value\)\] { - margin-bottom: var(--any-value); - } - .ml-\[var\(--any-value\)\] { - margin-left: var(--any-value); - } - .mr-\[var\(--any-value\)\] { - margin-right: var(--any-value); - } - .mt-\[var\(--any-value\)\] { - margin-top: var(--any-value); - } - .aspect-\[var\(--any-value\)\] { - aspect-ratio: var(--any-value); - } - .h-\[var\(--any-value\)\] { - height: var(--any-value); - } - .max-h-\[var\(--any-value\)\] { - max-height: var(--any-value); - } - .min-h-\[var\(--any-value\)\] { - min-height: var(--any-value); - } - .w-\[var\(--any-value\)\] { - width: var(--any-value); - } - .min-w-\[var\(--any-value\)\] { - min-width: var(--any-value); - } - .max-w-\[var\(--any-value\)\] { - max-width: var(--any-value); - } - .flex-\[var\(--any-value\)\] { - flex: var(--any-value); - } - .flex-shrink-\[var\(--any-value\)\], - .shrink-\[var\(--any-value\)\] { - flex-shrink: var(--any-value); - } - .flex-grow-\[var\(--any-value\)\], - .grow-\[var\(--any-value\)\] { - flex-grow: var(--any-value); - } - .basis-\[var\(--any-value\)\] { - flex-basis: var(--any-value); - } - .border-spacing-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-x-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-y-\[var\(--any-value\)\] { - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .origin-\[var\(--any-value\)\] { - transform-origin: var(--any-value); - } - .translate-x-\[var\(--any-value\)\] { - --tw-translate-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .translate-y-\[var\(--any-value\)\] { - --tw-translate-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .rotate-\[var\(--any-value\)\] { - --tw-rotate: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-y-\[var\(--any-value\)\] { - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .animate-\[var\(--any-value\)\] { - animation: var(--any-value); - } - .cursor-\[var\(--any-value\)\] { - cursor: var(--any-value); - } - .scroll-m-\[var\(--any-value\)\] { - scroll-margin: var(--any-value); - } - .scroll-mx-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - scroll-margin-right: var(--any-value); - } - .scroll-my-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - scroll-margin-bottom: var(--any-value); - } - .scroll-mb-\[var\(--any-value\)\] { - scroll-margin-bottom: var(--any-value); - } - .scroll-ml-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - } - .scroll-mr-\[var\(--any-value\)\] { - scroll-margin-right: var(--any-value); - } - .scroll-mt-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - } - .scroll-p-\[var\(--any-value\)\] { - scroll-padding: var(--any-value); - } - .scroll-px-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - scroll-padding-right: var(--any-value); - } - .scroll-py-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - scroll-padding-bottom: var(--any-value); - } - .scroll-pb-\[var\(--any-value\)\] { - scroll-padding-bottom: var(--any-value); - } - .scroll-pl-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - } - .scroll-pr-\[var\(--any-value\)\] { - scroll-padding-right: var(--any-value); - } - .scroll-pt-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - } - .list-\[var\(--any-value\)\] { - list-style-type: var(--any-value); - } - .columns-\[var\(--any-value\)\] { - columns: var(--any-value); - } - .auto-cols-\[var\(--any-value\)\] { - grid-auto-columns: var(--any-value); - } - .auto-rows-\[var\(--any-value\)\] { - grid-auto-rows: var(--any-value); - } - .grid-cols-\[var\(--any-value\)\] { - grid-template-columns: var(--any-value); - } - .grid-rows-\[var\(--any-value\)\] { - grid-template-rows: var(--any-value); - } - .gap-\[var\(--any-value\)\] { - gap: var(--any-value); - } - .gap-x-\[var\(--any-value\)\] { - column-gap: var(--any-value); - } - .gap-y-\[var\(--any-value\)\] { - row-gap: var(--any-value); - } - .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(var(--any-value) * var(--tw-space-x-reverse)); - margin-left: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); - } - .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); - } - .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); - } - .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--any-value); - } - .divide-opacity-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: var(--any-value); - } - .rounded-\[var\(--any-value\)\] { - border-radius: var(--any-value); - } - .rounded-b-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-l-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-r-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - border-bottom-right-radius: var(--any-value); - } - .rounded-t-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-top-right-radius: var(--any-value); - } - .rounded-bl-\[var\(--any-value\)\] { - border-bottom-left-radius: var(--any-value); - } - .rounded-br-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - } - .rounded-tl-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - } - .rounded-tr-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - } - .border-\[var\(--any-value\)\] { - border-color: var(--any-value); - } - .border-x-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - border-right-color: var(--any-value); - } - .border-y-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - border-bottom-color: var(--any-value); - } - .border-b-\[var\(--any-value\)\] { - border-bottom-color: var(--any-value); - } - .border-l-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - } - .border-r-\[var\(--any-value\)\] { - border-right-color: var(--any-value); - } - .border-t-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - } - .border-opacity-\[var\(--any-value\)\] { - --tw-border-opacity: var(--any-value); - } - .bg-\[var\(--any-value\)\] { - background-color: var(--any-value); - } - .bg-opacity-\[var\(--any-value\)\] { - --tw-bg-opacity: var(--any-value); - } - .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); - } - .fill-\[var\(--any-value\)\] { - fill: var(--any-value); - } - .stroke-\[var\(--any-value\)\] { - stroke: var(--any-value); - } - .object-\[var\(--any-value\)\] { - object-position: var(--any-value); - } - .p-\[var\(--any-value\)\] { - padding: var(--any-value); - } - .px-\[var\(--any-value\)\] { - padding-left: var(--any-value); - padding-right: var(--any-value); - } - .py-\[var\(--any-value\)\] { - padding-top: var(--any-value); - padding-bottom: var(--any-value); - } - .pb-\[var\(--any-value\)\] { - padding-bottom: var(--any-value); - } - .pl-\[var\(--any-value\)\] { - padding-left: var(--any-value); - } - .pr-\[var\(--any-value\)\] { - padding-right: var(--any-value); - } - .pt-\[var\(--any-value\)\] { - padding-top: var(--any-value); - } - .indent-\[var\(--any-value\)\] { - text-indent: var(--any-value); - } - .align-\[var\(--any-value\)\] { - vertical-align: var(--any-value); - } - .font-\[var\(--any-value\)\] { - font-weight: var(--any-value); - } - .leading-\[var\(--any-value\)\] { - line-height: var(--any-value); - } - .tracking-\[var\(--any-value\)\] { - letter-spacing: var(--any-value); - } - .text-\[var\(--any-value\)\] { - color: var(--any-value); - } - .text-opacity-\[var\(--any-value\)\] { - --tw-text-opacity: var(--any-value); - } - .decoration-\[var\(--any-value\)\] { - text-decoration-color: var(--any-value); - } - .underline-offset-\[var\(--any-value\)\] { - text-underline-offset: var(--any-value); - } - .placeholder-\[var\(--any-value\)\]::placeholder { - color: var(--any-value); - } - .placeholder-opacity-\[var\(--any-value\)\]::placeholder { - --tw-placeholder-opacity: var(--any-value); - } - .caret-\[var\(--any-value\)\] { - caret-color: var(--any-value); - } - .accent-\[var\(--any-value\)\] { - accent-color: var(--any-value); - } - .opacity-\[var\(--any-value\)\] { - opacity: var(--any-value); - } - .shadow-\[var\(--any-value\)\] { - --tw-shadow-color: var(--any-value); - --tw-shadow: var(--tw-shadow-colored); - } - .outline-offset-\[var\(--any-value\)\] { - outline-offset: var(--any-value); - } - .outline-\[var\(--any-value\)\] { - outline-color: var(--any-value); - } - .ring-\[var\(--any-value\)\] { - --tw-ring-color: var(--any-value); - } - .ring-opacity-\[var\(--any-value\)\] { - --tw-ring-opacity: var(--any-value); - } - .ring-offset-\[var\(--any-value\)\] { - --tw-ring-offset-color: var(--any-value); - } - .blur-\[var\(--any-value\)\] { - --tw-blur: blur(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .brightness-\[var\(--any-value\)\] { - --tw-brightness: brightness(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .contrast-\[var\(--any-value\)\] { - --tw-contrast: contrast(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .drop-shadow-\[var\(--any-value\)\] { - --tw-drop-shadow: drop-shadow(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .grayscale-\[var\(--any-value\)\] { - --tw-grayscale: grayscale(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .hue-rotate-\[var\(--any-value\)\] { - --tw-hue-rotate: hue-rotate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .invert-\[var\(--any-value\)\] { - --tw-invert: invert(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .saturate-\[var\(--any-value\)\] { - --tw-saturate: saturate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .sepia-\[var\(--any-value\)\] { - --tw-sepia: sepia(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .backdrop-blur-\[var\(--any-value\)\] { - --tw-backdrop-blur: blur(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-brightness-\[var\(--any-value\)\] { - --tw-backdrop-brightness: brightness(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-contrast-\[var\(--any-value\)\] { - --tw-backdrop-contrast: contrast(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-grayscale-\[var\(--any-value\)\] { - --tw-backdrop-grayscale: grayscale(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-hue-rotate-\[var\(--any-value\)\] { - --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-invert-\[var\(--any-value\)\] { - --tw-backdrop-invert: invert(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-opacity-\[var\(--any-value\)\] { - --tw-backdrop-opacity: opacity(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-saturate-\[var\(--any-value\)\] { - --tw-backdrop-saturate: saturate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-sepia-\[var\(--any-value\)\] { - --tw-backdrop-sepia: sepia(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .transition-\[var\(--any-value\)\] { - transition-property: var(--any-value); - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .delay-\[var\(--any-value\)\] { - transition-delay: var(--any-value); - } - .duration-\[var\(--any-value\)\] { - transition-duration: var(--any-value); - } - .ease-\[var\(--any-value\)\] { - transition-timing-function: var(--any-value); - } - .will-change-\[var\(--any-value\)\] { - will-change: var(--any-value); - } - .content-\[var\(--any-value\)\] { - --tw-content: var(--any-value); - content: var(--tw-content); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .inset-\[var\(--any-value\)\] { + inset: var(--any-value); + } + .inset-x-\[var\(--any-value\)\] { + left: var(--any-value); + right: var(--any-value); + } + .inset-y-\[var\(--any-value\)\] { + top: var(--any-value); + bottom: var(--any-value); + } + .bottom-\[var\(--any-value\)\] { + bottom: var(--any-value); + } + .left-\[var\(--any-value\)\] { + left: var(--any-value); + } + .right-\[var\(--any-value\)\] { + right: var(--any-value); + } + .top-\[var\(--any-value\)\] { + top: var(--any-value); + } + .z-\[var\(--any-value\)\] { + z-index: var(--any-value); + } + .order-\[var\(--any-value\)\] { + order: var(--any-value); + } + .col-\[var\(--any-value\)\] { + grid-column: var(--any-value); + } + .col-start-\[var\(--any-value\)\] { + grid-column-start: var(--any-value); + } + .col-end-\[var\(--any-value\)\] { + grid-column-end: var(--any-value); + } + .row-\[var\(--any-value\)\] { + grid-row: var(--any-value); + } + .row-start-\[var\(--any-value\)\] { + grid-row-start: var(--any-value); + } + .row-end-\[var\(--any-value\)\] { + grid-row-end: var(--any-value); + } + .m-\[var\(--any-value\)\] { + margin: var(--any-value); + } + .mx-\[var\(--any-value\)\] { + margin-left: var(--any-value); + margin-right: var(--any-value); + } + .my-\[var\(--any-value\)\] { + margin-top: var(--any-value); + margin-bottom: var(--any-value); + } + .mb-\[var\(--any-value\)\] { + margin-bottom: var(--any-value); + } + .ml-\[var\(--any-value\)\] { + margin-left: var(--any-value); + } + .mr-\[var\(--any-value\)\] { + margin-right: var(--any-value); + } + .mt-\[var\(--any-value\)\] { + margin-top: var(--any-value); + } + .aspect-\[var\(--any-value\)\] { + aspect-ratio: var(--any-value); + } + .h-\[var\(--any-value\)\] { + height: var(--any-value); + } + .max-h-\[var\(--any-value\)\] { + max-height: var(--any-value); + } + .min-h-\[var\(--any-value\)\] { + min-height: var(--any-value); + } + .w-\[var\(--any-value\)\] { + width: var(--any-value); + } + .min-w-\[var\(--any-value\)\] { + min-width: var(--any-value); + } + .max-w-\[var\(--any-value\)\] { + max-width: var(--any-value); + } + .flex-\[var\(--any-value\)\] { + flex: var(--any-value); + } + .flex-shrink-\[var\(--any-value\)\], + .shrink-\[var\(--any-value\)\] { + flex-shrink: var(--any-value); + } + .flex-grow-\[var\(--any-value\)\], + .grow-\[var\(--any-value\)\] { + flex-grow: var(--any-value); + } + .basis-\[var\(--any-value\)\] { + flex-basis: var(--any-value); + } + .border-spacing-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-x-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-y-\[var\(--any-value\)\] { + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .origin-\[var\(--any-value\)\] { + transform-origin: var(--any-value); + } + .translate-x-\[var\(--any-value\)\] { + --tw-translate-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .translate-y-\[var\(--any-value\)\] { + --tw-translate-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .rotate-\[var\(--any-value\)\] { + --tw-rotate: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-x-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-y-\[var\(--any-value\)\] { + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .animate-\[var\(--any-value\)\] { + animation: var(--any-value); + } + .cursor-\[var\(--any-value\)\] { + cursor: var(--any-value); + } + .scroll-m-\[var\(--any-value\)\] { + scroll-margin: var(--any-value); + } + .scroll-mx-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + scroll-margin-right: var(--any-value); + } + .scroll-my-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + scroll-margin-bottom: var(--any-value); + } + .scroll-mb-\[var\(--any-value\)\] { + scroll-margin-bottom: var(--any-value); + } + .scroll-ml-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + } + .scroll-mr-\[var\(--any-value\)\] { + scroll-margin-right: var(--any-value); + } + .scroll-mt-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + } + .scroll-p-\[var\(--any-value\)\] { + scroll-padding: var(--any-value); + } + .scroll-px-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + scroll-padding-right: var(--any-value); + } + .scroll-py-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + scroll-padding-bottom: var(--any-value); + } + .scroll-pb-\[var\(--any-value\)\] { + scroll-padding-bottom: var(--any-value); + } + .scroll-pl-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + } + .scroll-pr-\[var\(--any-value\)\] { + scroll-padding-right: var(--any-value); + } + .scroll-pt-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + } + .list-\[var\(--any-value\)\] { + list-style-type: var(--any-value); + } + .columns-\[var\(--any-value\)\] { + columns: var(--any-value); + } + .auto-cols-\[var\(--any-value\)\] { + grid-auto-columns: var(--any-value); + } + .auto-rows-\[var\(--any-value\)\] { + grid-auto-rows: var(--any-value); + } + .grid-cols-\[var\(--any-value\)\] { + grid-template-columns: var(--any-value); + } + .grid-rows-\[var\(--any-value\)\] { + grid-template-rows: var(--any-value); + } + .gap-\[var\(--any-value\)\] { + gap: var(--any-value); + } + .gap-x-\[var\(--any-value\)\] { + column-gap: var(--any-value); + } + .gap-y-\[var\(--any-value\)\] { + row-gap: var(--any-value); + } + .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(var(--any-value) * var(--tw-space-x-reverse)); + margin-left: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); + } + .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); + } + .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); + } + .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: var(--any-value); + } + .divide-opacity-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: var(--any-value); + } + .rounded-\[var\(--any-value\)\] { + border-radius: var(--any-value); + } + .rounded-b-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-l-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-r-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + border-bottom-right-radius: var(--any-value); + } + .rounded-t-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-top-right-radius: var(--any-value); + } + .rounded-bl-\[var\(--any-value\)\] { + border-bottom-left-radius: var(--any-value); + } + .rounded-br-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + } + .rounded-tl-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + } + .rounded-tr-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + } + .border-\[var\(--any-value\)\] { + border-color: var(--any-value); + } + .border-x-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + border-right-color: var(--any-value); + } + .border-y-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + border-bottom-color: var(--any-value); + } + .border-b-\[var\(--any-value\)\] { + border-bottom-color: var(--any-value); + } + .border-l-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + } + .border-r-\[var\(--any-value\)\] { + border-right-color: var(--any-value); + } + .border-t-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + } + .border-opacity-\[var\(--any-value\)\] { + --tw-border-opacity: var(--any-value); + } + .bg-\[var\(--any-value\)\] { + background-color: var(--any-value); + } + .bg-opacity-\[var\(--any-value\)\] { + --tw-bg-opacity: var(--any-value); + } + .from-\[var\(--any-value\)\] { + --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .via-\[var\(--any-value\)\] { + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), + var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); + } + .to-\[var\(--any-value\)\] { + --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); + } + .fill-\[var\(--any-value\)\] { + fill: var(--any-value); + } + .stroke-\[var\(--any-value\)\] { + stroke: var(--any-value); + } + .object-\[var\(--any-value\)\] { + object-position: var(--any-value); + } + .p-\[var\(--any-value\)\] { + padding: var(--any-value); + } + .px-\[var\(--any-value\)\] { + padding-left: var(--any-value); + padding-right: var(--any-value); + } + .py-\[var\(--any-value\)\] { + padding-top: var(--any-value); + padding-bottom: var(--any-value); + } + .pb-\[var\(--any-value\)\] { + padding-bottom: var(--any-value); + } + .pl-\[var\(--any-value\)\] { + padding-left: var(--any-value); + } + .pr-\[var\(--any-value\)\] { + padding-right: var(--any-value); + } + .pt-\[var\(--any-value\)\] { + padding-top: var(--any-value); + } + .indent-\[var\(--any-value\)\] { + text-indent: var(--any-value); + } + .align-\[var\(--any-value\)\] { + vertical-align: var(--any-value); + } + .font-\[var\(--any-value\)\] { + font-weight: var(--any-value); + } + .leading-\[var\(--any-value\)\] { + line-height: var(--any-value); + } + .tracking-\[var\(--any-value\)\] { + letter-spacing: var(--any-value); + } + .text-\[var\(--any-value\)\] { + color: var(--any-value); + } + .text-opacity-\[var\(--any-value\)\] { + --tw-text-opacity: var(--any-value); + } + .decoration-\[var\(--any-value\)\] { + -webkit-text-decoration-color: var(--any-value); + text-decoration-color: var(--any-value); + } + .underline-offset-\[var\(--any-value\)\] { + text-underline-offset: var(--any-value); + } + .placeholder-\[var\(--any-value\)\]::placeholder { + color: var(--any-value); + } + .placeholder-opacity-\[var\(--any-value\)\]::placeholder { + --tw-placeholder-opacity: var(--any-value); + } + .caret-\[var\(--any-value\)\] { + caret-color: var(--any-value); + } + .accent-\[var\(--any-value\)\] { + accent-color: var(--any-value); + } + .opacity-\[var\(--any-value\)\] { + opacity: var(--any-value); + } + .shadow-\[var\(--any-value\)\] { + --tw-shadow-color: var(--any-value); + --tw-shadow: var(--tw-shadow-colored); + } + .outline-offset-\[var\(--any-value\)\] { + outline-offset: var(--any-value); + } + .outline-\[var\(--any-value\)\] { + outline-color: var(--any-value); + } + .ring-\[var\(--any-value\)\] { + --tw-ring-color: var(--any-value); + } + .ring-opacity-\[var\(--any-value\)\] { + --tw-ring-opacity: var(--any-value); + } + .ring-offset-\[var\(--any-value\)\] { + --tw-ring-offset-color: var(--any-value); + } + .blur-\[var\(--any-value\)\] { + --tw-blur: blur(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .brightness-\[var\(--any-value\)\] { + --tw-brightness: brightness(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .contrast-\[var\(--any-value\)\] { + --tw-contrast: contrast(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .drop-shadow-\[var\(--any-value\)\] { + --tw-drop-shadow: drop-shadow(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .grayscale-\[var\(--any-value\)\] { + --tw-grayscale: grayscale(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .hue-rotate-\[var\(--any-value\)\] { + --tw-hue-rotate: hue-rotate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .invert-\[var\(--any-value\)\] { + --tw-invert: invert(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .saturate-\[var\(--any-value\)\] { + --tw-saturate: saturate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .sepia-\[var\(--any-value\)\] { + --tw-sepia: sepia(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .backdrop-blur-\[var\(--any-value\)\] { + --tw-backdrop-blur: blur(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-brightness-\[var\(--any-value\)\] { + --tw-backdrop-brightness: brightness(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-contrast-\[var\(--any-value\)\] { + --tw-backdrop-contrast: contrast(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-grayscale-\[var\(--any-value\)\] { + --tw-backdrop-grayscale: grayscale(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-hue-rotate-\[var\(--any-value\)\] { + --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-invert-\[var\(--any-value\)\] { + --tw-backdrop-invert: invert(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-opacity-\[var\(--any-value\)\] { + --tw-backdrop-opacity: opacity(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-saturate-\[var\(--any-value\)\] { + --tw-backdrop-saturate: saturate(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-sepia-\[var\(--any-value\)\] { + --tw-backdrop-sepia: sepia(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .transition-\[var\(--any-value\)\] { + transition-property: var(--any-value); + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + .delay-\[var\(--any-value\)\] { + transition-delay: var(--any-value); + } + .duration-\[var\(--any-value\)\] { + transition-duration: var(--any-value); + } + .ease-\[var\(--any-value\)\] { + transition-timing-function: var(--any-value); + } + .will-change-\[var\(--any-value\)\] { + will-change: var(--any-value); + } + .content-\[var\(--any-value\)\] { + --tw-content: var(--any-value); + content: var(--tw-content); + } + `) }) - test.todo('rewrite the any test to be easier to understand or break it up into multiple tests') }) +test.todo('rewrite the any test to be easier to understand or break it up into multiple tests') diff --git a/tests/apply.test.js b/tests/apply.test.js index e4af6ee58..e0c324bf9 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -1,2473 +1,2083 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - let sharedHtml = html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+let sharedHtml = html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+` + +test('@apply', () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .basic-example { + @apply rounded-md bg-blue-500 px-4 py-2; + } + .class-order { + @apply p-8 px-3 py-7 pt-4 pr-1; + } + .with-additional-properties { + font-weight: 500; + @apply text-right; + } + .variants { + @apply font-semibold hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + } + .only-variants { + @apply hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + } + .apply-group-variant { + @apply group-hover:text-center lg:group-hover:text-left; + } + .apply-dark-variant { + @apply dark:text-center dark:hover:text-right lg:dark:text-left; + } + .apply-custom-utility { + @apply custom-util hover:custom-util lg:custom-util xl:focus:custom-util; + } + .multiple, + .selectors { + @apply rounded-md bg-blue-500 px-4 py-2; + } + .multiple-variants, + .selectors-variants { + @apply hover:text-center active:text-right lg:focus:text-left; + } + .multiple-group, + .selectors-group { + @apply group-hover:text-center lg:group-hover:text-left; + } + .complex-utilities { + @apply ordinal tabular-nums shadow-lg hover:shadow-xl focus:diagonal-fractions; + } + .use-base-only-a { + @apply font-bold; + } + .use-base-only-b { + @apply use-base-only-a font-normal; + } + .use-dependant-only-a { + @apply font-bold; + } + .use-dependant-only-b { + @apply use-dependant-only-a font-normal; + } + .btn { + @apply rounded py-2 px-4 font-bold; + } + .btn-blue { + @apply btn bg-blue-500 text-white hover:bg-blue-700; + } + .recursive-apply-a { + @apply font-black sm:font-thin; + } + .recursive-apply-b { + @apply recursive-apply-a font-semibold md:font-extralight; + } + .recursive-apply-c { + @apply recursive-apply-b font-bold lg:font-light; + } + .use-with-other-properties-base { + color: green; + @apply font-bold; + } + .use-with-other-properties-component { + @apply use-with-other-properties-base; + } + .add-sibling-properties { + padding: 2rem; + @apply px-4 hover:px-2 lg:px-10 xl:focus:px-1; + padding-top: 3px; + @apply use-with-other-properties-base; + } + + h1 { + @apply text-2xl sm:text-3xl lg:text-2xl; + } + h2 { + @apply text-2xl; + @apply lg:text-2xl; + @apply sm:text-2xl; + } + + .important-modifier { + @apply !rounded-md px-4; + } + + .important-modifier-variant { + @apply px-4 hover:!rounded-md; + } + } + + @layer utilities { + .custom-util { + custom: stuff; + } + + .foo { + @apply animate-spin; + } + + .bar { + @apply animate-pulse !important; + } + } ` - test('@apply', () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .basic-example { - @apply rounded-md bg-blue-500 px-4 py-2; - } - .class-order { - @apply p-8 px-3 py-7 pt-4 pr-1; - } - .with-additional-properties { - font-weight: 500; - @apply text-right; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .basic-example { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + border-radius: 0.375rem; + padding: 0.5rem 1rem; + } + .class-order { + padding: 1rem 0.25rem 1.75rem 0.75rem; + } + .with-additional-properties { + text-align: right; + font-weight: 500; + } + .variants { + font-weight: 600; + } + .variants:hover { + font-weight: 700; + } + .variants:focus { + font-weight: 500; + } + @media (min-width: 1024px) { .variants { - @apply font-semibold hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + font-weight: 300; } + } + @media (min-width: 1280px) { + .variants:focus { + font-weight: 900; + } + } + .only-variants:hover { + font-weight: 700; + } + .only-variants:focus { + font-weight: 500; + } + @media (min-width: 1024px) { .only-variants { - @apply hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + font-weight: 300; } - .apply-group-variant { - @apply group-hover:text-center lg:group-hover:text-left; + } + @media (min-width: 1280px) { + .only-variants:focus { + font-weight: 900; } - .apply-dark-variant { - @apply dark:text-center dark:hover:text-right lg:dark:text-left; + } + .group:hover .apply-group-variant { + text-align: center; + } + @media (min-width: 1024px) { + .group:hover .apply-group-variant { + text-align: left; } + } + :is(.dark .apply-dark-variant) { + text-align: center; + } + :is(.dark .apply-dark-variant:hover) { + text-align: right; + } + @media (min-width: 1024px) { + :is(.dark .apply-dark-variant) { + text-align: left; + } + } + .apply-custom-utility, + .apply-custom-utility:hover { + custom: stuff; + } + @media (min-width: 1024px) { .apply-custom-utility { - @apply custom-util hover:custom-util lg:custom-util xl:focus:custom-util; - } - .multiple, - .selectors { - @apply rounded-md bg-blue-500 px-4 py-2; - } - .multiple-variants, - .selectors-variants { - @apply hover:text-center active:text-right lg:focus:text-left; - } - .multiple-group, - .selectors-group { - @apply group-hover:text-center lg:group-hover:text-left; - } - .complex-utilities { - @apply ordinal tabular-nums shadow-lg hover:shadow-xl focus:diagonal-fractions; - } - .use-base-only-a { - @apply font-bold; - } - .use-base-only-b { - @apply use-base-only-a font-normal; - } - .use-dependant-only-a { - @apply font-bold; - } - .use-dependant-only-b { - @apply use-dependant-only-a font-normal; - } - .btn { - @apply rounded py-2 px-4 font-bold; - } - .btn-blue { - @apply btn bg-blue-500 text-white hover:bg-blue-700; - } - .recursive-apply-a { - @apply font-black sm:font-thin; - } - .recursive-apply-b { - @apply recursive-apply-a font-semibold md:font-extralight; - } - .recursive-apply-c { - @apply recursive-apply-b font-bold lg:font-light; - } - .use-with-other-properties-base { - color: green; - @apply font-bold; - } - .use-with-other-properties-component { - @apply use-with-other-properties-base; - } - .add-sibling-properties { - padding: 2rem; - @apply px-4 hover:px-2 lg:px-10 xl:focus:px-1; - padding-top: 3px; - @apply use-with-other-properties-base; - } - - h1 { - @apply text-2xl sm:text-3xl lg:text-2xl; - } - h2 { - @apply text-2xl; - @apply lg:text-2xl; - @apply sm:text-2xl; - } - - .important-modifier { - @apply !rounded-md px-4; - } - - .important-modifier-variant { - @apply px-4 hover:!rounded-md; - } - } - - @layer utilities { - .custom-util { custom: stuff; } - - .foo { - @apply animate-spin; - } - - .bar { - @apply animate-pulse !important; - } } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .basic-example { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .class-order { - padding: 1rem 0.25rem 1.75rem 0.75rem; - } - .with-additional-properties { - text-align: right; - font-weight: 500; - } - .variants { - font-weight: 600; - } - .variants:hover { - font-weight: 700; - } - .variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .variants:focus { - font-weight: 900; - } - } - .only-variants:hover { - font-weight: 700; - } - .only-variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .only-variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .only-variants:focus { - font-weight: 900; - } - } - .group:hover .apply-group-variant { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .apply-group-variant { - text-align: left; - } - } - :is(.dark .apply-dark-variant) { - text-align: center; - } - :is(.dark .apply-dark-variant:hover) { - text-align: right; - } - @media (min-width: 1024px) { - :is(.dark .apply-dark-variant) { - text-align: left; - } - } - .apply-custom-utility, - .apply-custom-utility:hover { + @media (min-width: 1280px) { + .apply-custom-utility:focus { custom: stuff; } - @media (min-width: 1024px) { - .apply-custom-utility { - custom: stuff; - } - } - @media (min-width: 1280px) { - .apply-custom-utility:focus { - custom: stuff; - } - } - .multiple, - .selectors { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .multiple-variants:hover, - .selectors-variants:hover { - text-align: center; - } - .multiple-variants:active, - .selectors-variants:active { - text-align: right; - } - @media (min-width: 1024px) { - .multiple-variants:focus, - .selectors-variants:focus { - text-align: left; - } + } + .multiple, + .selectors { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + border-radius: 0.375rem; + padding: 0.5rem 1rem; + } + .multiple-variants:hover, + .selectors-variants:hover { + text-align: center; + } + .multiple-variants:active, + .selectors-variants:active { + text-align: right; + } + @media (min-width: 1024px) { + .multiple-variants:focus, + .selectors-variants:focus { + text-align: left; } + } + .group:hover .multiple-group, + .group:hover .selectors-group { + text-align: center; + } + @media (min-width: 1024px) { .group:hover .multiple-group, .group:hover .selectors-group { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: left; - } - } - .complex-utilities { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:hover { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:focus { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .use-base-only-a { - font-weight: 700; - } - .use-dependant-only-b { - font-weight: 400; - } - .btn { - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity)); + text-align: left; } + } + .complex-utilities { + --tw-ordinal: ordinal; + --tw-numeric-spacing: tabular-nums; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), + 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .complex-utilities:hover { + --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), + 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .complex-utilities:focus { + --tw-numeric-fraction: diagonal-fractions; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + } + .use-base-only-a { + font-weight: 700; + } + .use-dependant-only-b { + font-weight: 400; + } + .btn { + border-radius: 0.25rem; + padding: 0.5rem 1rem; + font-weight: 700; + } + .btn-blue { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + border-radius: 0.25rem; + padding: 0.5rem 1rem; + font-weight: 700; + } + .btn-blue:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); + } + .recursive-apply-a { + font-weight: 900; + } + @media (min-width: 640px) { .recursive-apply-a { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-a { - font-weight: 100; - } + font-weight: 100; } + } + @media (min-width: 640px) { .recursive-apply-b { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-b { - font-weight: 100; - } + font-weight: 100; } + } + .recursive-apply-b { + font-weight: 600; + } + @media (min-width: 768px) { .recursive-apply-b { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-b { - font-weight: 200; - } + font-weight: 200; } + } + @media (min-width: 640px) { .recursive-apply-c { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-c { - font-weight: 100; - } + font-weight: 100; } + } + @media (min-width: 768px) { .recursive-apply-c { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-c { - font-weight: 200; - } + font-weight: 200; } + } + .recursive-apply-c { + font-weight: 700; + } + @media (min-width: 1024px) { .recursive-apply-c { - font-weight: 700; - } - @media (min-width: 1024px) { - .recursive-apply-c { - font-weight: 300; - } - } - .use-with-other-properties-base, - .use-with-other-properties-component { - color: green; - font-weight: 700; + font-weight: 300; } + } + .use-with-other-properties-base, + .use-with-other-properties-component { + color: green; + font-weight: 700; + } + .add-sibling-properties { + padding: 2rem 1rem; + } + .add-sibling-properties:hover { + padding-left: 0.5rem; + padding-right: 0.5rem; + } + @media (min-width: 1024px) { .add-sibling-properties { - padding: 2rem 1rem; + padding-left: 2.5rem; + padding-right: 2.5rem; } - .add-sibling-properties:hover { - padding-left: 0.5rem; - padding-right: 0.5rem; + } + @media (min-width: 1280px) { + .add-sibling-properties:focus { + padding-left: 0.25rem; + padding-right: 0.25rem; } - @media (min-width: 1024px) { - .add-sibling-properties { - padding-left: 2.5rem; - padding-right: 2.5rem; - } - } - @media (min-width: 1280px) { - .add-sibling-properties:focus { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - } - .add-sibling-properties { - color: green; - padding-top: 3px; - font-weight: 700; + } + .add-sibling-properties { + color: green; + padding-top: 3px; + font-weight: 700; + } + h1 { + font-size: 1.5rem; + line-height: 2rem; + } + @media (min-width: 640px) { + h1 { + font-size: 1.875rem; + line-height: 2.25rem; } + } + @media (min-width: 1024px) { h1 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 640px) { - h1 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 1024px) { - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - } + } + h2 { + font-size: 1.5rem; + line-height: 2rem; + } + @media (min-width: 1024px) { h2 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 1024px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - .important-modifier { - padding-left: 1rem; - padding-right: 1rem; - border-radius: 0.375rem !important; - } - .important-modifier-variant { - padding-left: 1rem; - padding-right: 1rem; - } - .important-modifier-variant:hover { - border-radius: 0.375rem !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .foo { - animation: 1s linear infinite spin; - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .bar { - animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .basic-example { - background-color: #3b82f6; - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .class-order { - padding: 1rem 0.25rem 1.75rem 0.75rem; - } - .with-additional-properties { - text-align: right; - font-weight: 500; - } - .variants { - font-weight: 600; - } - .variants:hover { - font-weight: 700; - } - .variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .variants:focus { - font-weight: 900; - } - } - .only-variants:hover { - font-weight: 700; - } - .only-variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .only-variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .only-variants:focus { - font-weight: 900; - } - } - .group:hover .apply-group-variant { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .apply-group-variant { - text-align: left; - } - } - :is(.dark .apply-dark-variant) { - text-align: center; - } - :is(.dark .apply-dark-variant:hover) { - text-align: right; - } - @media (min-width: 1024px) { - :is(.dark .apply-dark-variant) { - text-align: left; - } - } - .apply-custom-utility, - .apply-custom-utility:hover { - custom: stuff; - } - @media (min-width: 1024px) { - .apply-custom-utility { - custom: stuff; - } - } - @media (min-width: 1280px) { - .apply-custom-utility:focus { - custom: stuff; - } - } - .multiple, - .selectors { - background-color: #3b82f6; - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .multiple-variants:hover, - .selectors-variants:hover { - text-align: center; - } - .multiple-variants:active, - .selectors-variants:active { - text-align: right; - } - @media (min-width: 1024px) { - .multiple-variants:focus, - .selectors-variants:focus { - text-align: left; - } - } - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: left; - } - } - .complex-utilities { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:hover { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:focus { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .use-base-only-a { - font-weight: 700; - } - .use-dependant-only-b { - font-weight: 400; - } - .btn { - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue { - color: #fff; - background-color: #3b82f6; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue:hover { - background-color: #1d4ed8; - } - .recursive-apply-a { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-a { - font-weight: 100; - } - } - .recursive-apply-b { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-b { - font-weight: 100; - } - } - .recursive-apply-b { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-b { - font-weight: 200; - } - } - .recursive-apply-c { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-c { - font-weight: 100; - } - } - .recursive-apply-c { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-c { - font-weight: 200; - } - } - .recursive-apply-c { - font-weight: 700; - } - @media (min-width: 1024px) { - .recursive-apply-c { - font-weight: 300; - } - } - .use-with-other-properties-base, - .use-with-other-properties-component { - color: green; - font-weight: 700; - } - .add-sibling-properties { - padding: 2rem 1rem; - } - .add-sibling-properties:hover { - padding-left: 0.5rem; - padding-right: 0.5rem; - } - @media (min-width: 1024px) { - .add-sibling-properties { - padding-left: 2.5rem; - padding-right: 2.5rem; - } - } - @media (min-width: 1280px) { - .add-sibling-properties:focus { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - } - .add-sibling-properties { - color: green; - padding-top: 3px; - font-weight: 700; - } - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - @media (min-width: 640px) { - h1 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 1024px) { - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - } + } + @media (min-width: 640px) { h2 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 1024px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - .important-modifier { - padding-left: 1rem; - padding-right: 1rem; - border-radius: 0.375rem !important; - } - .important-modifier-variant { - padding-left: 1rem; - padding-right: 1rem; - } - .important-modifier-variant:hover { - border-radius: 0.375rem !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .foo { - animation: 1s linear infinite spin; - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .bar { - animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; - } - `) - }) - }) - - test('@apply error with unknown utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply a-utility-that-does-not-exist; + } + .important-modifier { + padding-left: 1rem; + padding-right: 1rem; + border-radius: 0.375rem !important; + } + .important-modifier-variant { + padding-left: 1rem; + padding-right: 1rem; + } + .important-modifier-variant:hover { + border-radius: 0.375rem !important; + } + @keyframes spin { + to { + transform: rotate(360deg); } } - ` - - await expect(run(input, config)).rejects.toThrowError('class does not exist') - }) - - test('@apply error with nested @screen', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @screen md { - @apply text-black; - } - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - '@apply is not supported within nested at-rules like @screen' - ) - }) - - test('@apply error with nested @anyatrulehere', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @genie { - @apply text-black; - } - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - '@apply is not supported within nested at-rules like @genie' - ) - }) - - test('@apply error when using .group utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: '
' }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply group; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'group' utility` - ) - }) - - test('@apply error when using a prefixed .group utility', async () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply tw-group; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'tw-group' utility` - ) - }) - - test('@apply error when using .peer utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: '
' }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply peer; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'peer' utility` - ) - }) - - test('@apply error when using a prefixed .peer utility', async () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply tw-peer; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'tw-peer' utility` - ) - }) - - test('@apply classes from outside a @layer', async () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - .foo { - @apply font-bold; + animation: 1s linear infinite spin; + } + @keyframes pulse { + 50% { + opacity: 0.5; + } } - .bar { - @apply foo text-red-500 hover:text-green-500; + animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; } + `) + }) +}) +test('@apply error with unknown utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply a-utility-that-does-not-exist; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError('class does not exist') +}) + +test('@apply error with nested @screen', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @screen md { + @apply text-black; + } + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + '@apply is not supported within nested at-rules like @screen' + ) +}) + +test('@apply error with nested @anyatrulehere', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @genie { + @apply text-black; + } + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + '@apply is not supported within nested at-rules like @genie' + ) +}) + +test('@apply error when using .group utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: '
' }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply group; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'group' utility` + ) +}) + +test('@apply error when using a prefixed .group utility', async () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply tw-group; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'tw-group' utility` + ) +}) + +test('@apply error when using .peer utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: '
' }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply peer; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'peer' utility` + ) +}) + +test('@apply error when using a prefixed .peer utility', async () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply tw-peer; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'tw-peer' utility` + ) +}) + +test('@apply classes from outside a @layer', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + @apply font-bold; + } + + .bar { + @apply foo text-red-500 hover:text-green-500; + } + + .baz { + @apply bar underline; + } + + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + ` + + await run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .foo { + font-weight: 700; + } + .bar { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); + font-weight: 700; + } + .bar:hover { + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); + } .baz { - @apply bar underline; + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); + font-weight: 700; + text-decoration-line: underline; + } + .baz:hover { + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); } - .keep-me-even-though-I-am-not-used-in-content { color: green; } - ` - - await run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .font-bold, - .foo { - font-weight: 700; - } - .bar { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - font-weight: 700; - } - .bar:hover { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - } - .baz { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - font-weight: 700; - text-decoration-line: underline; - } - .baz:hover { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .font-bold, - .foo { - font-weight: 700; - } - .bar { - color: #ef4444; - font-weight: 700; - } - .bar:hover { - color: #22c55e; - } - .baz { - color: #ef4444; - font-weight: 700; - text-decoration-line: underline; - } - .baz:hover { - color: #22c55e; - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - `) - }) + `) }) +}) - test('@applying classes from outside a @layer respects the source order', async () => { - let config = { - content: [{ raw: html`
` }], +test('@applying classes from outside a @layer respects the source order', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + .baz { + @apply bar underline; } - let input = css` + @tailwind components; + + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + + @tailwind utilities; + + .foo { + @apply font-bold; + } + + .bar { + @apply no-underline; + } + ` + + await run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` .baz { - @apply bar underline; + text-decoration-line: none; } - - @tailwind components; - - .keep-me-even-though-I-am-not-used-in-content { - color: green; + .container { + width: 100%; } - - @tailwind utilities; - - .foo { - @apply font-bold; - } - - .bar { - @apply no-underline; - } - ` - - await run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .baz { - text-decoration-line: none; - } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 768px) { + .container { + max-width: 768px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - .font-bold, - .foo { - font-weight: 700; - } - .bar { - text-decoration-line: none; - } - `) - }) - }) - - it('should remove duplicate properties when using apply with similar properties', () => { - let config = { - content: [{ raw: 'foo' }], - } - - let input = css` - @tailwind utilities; - + } + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + .font-bold, .foo { - @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform; + font-weight: 700; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - --tw-translate-x: -50%; - --tw-translate-y: -50%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - position: absolute; - top: 50%; - left: 50%; - } - `) - }) + .bar { + text-decoration-line: none; + } + `) }) +}) - it('should apply all the definitions of a class', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should remove duplicate properties when using apply with similar properties', () => { + let config = { + content: [{ raw: 'foo' }], + } + + let input = css` + @tailwind utilities; + + .foo { + @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + --tw-translate-x: -50%; + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + position: absolute; + top: 50%; + left: 50%; + } + `) + }) +}) + +it('should apply all the definitions of a class', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer utilities { + .aspect-w-1 { + position: relative; + } + + .aspect-w-1 { + --tw-aspect-w: 1; + } } - let input = css` - @tailwind components; - @tailwind utilities; - - @layer utilities { - .aspect-w-1 { - position: relative; - } - - .aspect-w-1 { - --tw-aspect-w: 1; - } + @layer components { + .foo { + @apply aspect-w-1; } - - @layer components { - .foo { - @apply aspect-w-1; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo { - --tw-aspect-w: 1; - position: relative; - } - `) - }) - }) - - it('should throw when trying to apply a direct circular dependency', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], } + ` - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo:not(.text-red-500) { - @apply text-red-500; - } + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo { + --tw-aspect-w: 1; + position: relative; } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `text-red-500` utility here because it creates a circular dependency.' - ) - }) + `) }) +}) - it('should throw when trying to apply an indirect circular dependency', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } +it('should throw when trying to apply a direct circular dependency', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - @layer components { - .a { - @apply b; - } - - .b { - @apply c; - } - - .c { - @apply a; - } + @layer components { + .foo:not(.text-red-500) { + @apply text-red-500; } - ` + } + ` - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' - ) - }) + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `text-red-500` utility here because it creates a circular dependency.' + ) }) +}) - it('should not throw when the selector is different (but contains the base partially)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } +it('should throw when trying to apply an indirect circular dependency', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - .focus\:bg-gray-500 { - @apply bg-gray-500; - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-gray-500, - .focus\:bg-gray-500 { - --tw-bg-opacity: 1; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-gray-500, - .focus\:bg-gray-500 { - background-color: #6b7280; - } - `) - }) - }) - - it('should throw when trying to apply an indirect circular dependency with a modifier (1)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .a { - @apply b; - } - - .b { - @apply c; - } - - .c { - @apply hover:a; - } - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `hover:a` utility here because it creates a circular dependency.' - ) - }) - }) - - it('should throw when trying to apply an indirect circular dependency with a modifier (2)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .a { - @apply b; - } - - .b { - @apply hover:c; - } - - .c { - @apply a; - } - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' - ) - }) - }) - - it('should not throw when the circular dependency is part of a different selector (1)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - .b { - color: red; - } - } - - html.dark .c { + @layer components { + .a { @apply b; } - ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - html.dark .c { - color: red; - } - `) - }) - }) + .b { + @apply c; + } - it('should not throw when the circular dependency is part of a different selector (2)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + .c { + @apply a; + } } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - .b { - color: red; - } - } - - html.dark .c { - @apply hover:b; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - html.dark .c:hover { - color: red; - } - `) - }) + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' + ) }) +}) - it('should throw when the circular dependency is part of the same selector', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should not throw when the selector is different (but contains the base partially)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .focus\:bg-gray-500 { + @apply bg-gray-500; } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - html.dark .b { - color: red; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-gray-500, + .focus\:bg-gray-500 { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); } - - html.dark .c { - @apply hover:b; - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `hover:b` utility here because it creates a circular dependency.' - ) - }) + `) }) +}) - it('rules with vendor prefixes are still separate when optimizing defaults rules', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should throw when trying to apply an indirect circular dependency with a modifier (1)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - @layer components { - input[type='range']::-moz-range-thumb { - @apply border; - } + @layer components { + .a { + @apply b; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - input[type='range']::-moz-range-thumb { - border-width: 1px; - } - .border { - border-width: 1px; - } - `) - }) - }) + .b { + @apply c; + } - it('should be possible to apply user css', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + .c { + @apply hover:a; + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `hover:a` utility here because it creates a circular dependency.' + ) + }) +}) - .foo { +it('should throw when trying to apply an indirect circular dependency with a modifier (2)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .a { + @apply b; + } + + .b { + @apply hover:c; + } + + .c { + @apply a; + } + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' + ) + }) +}) + +it('should not throw when the circular dependency is part of a different selector (1)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + .b { color: red; } + } + + html.dark .c { + @apply b; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + html.dark .c { + color: red; + } + `) + }) +}) + +it('should not throw when the circular dependency is part of a different selector (2)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + .b { + color: red; + } + } + + html.dark .c { + @apply hover:b; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + html.dark .c:hover { + color: red; + } + `) + }) +}) + +it('should throw when the circular dependency is part of the same selector', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + html.dark .b { + color: red; + } + } + + html.dark .c { + @apply hover:b; + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `hover:b` utility here because it creates a circular dependency.' + ) + }) +}) + +it('rules with vendor prefixes are still separate when optimizing defaults rules', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer components { + input[type='range']::-moz-range-thumb { + @apply border; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + input[type='range']::-moz-range-thumb { + border-width: 1px; + } + .border { + border-width: 1px; + } + `) + }) +}) + +it('should be possible to apply user css', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + + .bar { + @apply foo; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: red; + } + `) + }) +}) + +it('should not be possible to apply user css with variants', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + + .bar { + @apply hover:foo; + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'The `hover:foo` class does not exist. If `hover:foo` is a custom class, make sure it is defined within a `@layer` directive.' + ) + }) +}) + +it('should not apply unrelated siblings when applying something from within atrules', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + font-weight: bold; + @apply bar; + } .bar { - @apply foo; + color: green; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo, + @supports (a: b) { .bar { + color: blue; + } + + .something-unrelated { color: red; } - `) - }) - }) - - it('should not be possible to apply user css with variants', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; - + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` .foo { - color: red; + color: green; + font-weight: bold; + } + @supports (a: b) { + .foo { + color: #00f; + } } - .bar { - @apply hover:foo; + color: green; } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'The `hover:foo` class does not exist. If `hover:foo` is a custom class, make sure it is defined within a `@layer` directive.' - ) - }) - }) - - it('should not apply unrelated siblings when applying something from within atrules', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - font-weight: bold; - @apply bar; - } - + @supports (a: b) { .bar { - color: green; + color: #00f; } - - @supports (a: b) { - .bar { - color: blue; - } - - .something-unrelated { - color: red; - } + .something-unrelated { + color: red; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - color: green; - font-weight: bold; - } - @supports (a: b) { - .foo { - color: #00f; - } - } - .bar { - color: green; - } - @supports (a: b) { - .bar { - color: #00f; - } - .something-unrelated { - color: red; - } - } - `) - }) + `) }) +}) - it('should be possible to apply user css without tailwind directives', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should be possible to apply user css without tailwind directives', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .bop { + color: red; } + .bar { + background-color: blue; + } + .foo { + @apply bar bop absolute; + } + ` - let input = css` + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` .bop { color: red; } .bar { - background-color: blue; + background-color: #00f; } .foo { - @apply bar bop absolute; + color: red; + background-color: #00f; + position: absolute; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (2 classes)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .c { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 tag)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + span, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + span, + .b, + .c { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 id)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { + #a, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + #a, + .b, + .c { + text-decoration-line: underline; + } + `) + }) +}) + +describe('multiple instances', () => { + it('should be possible to apply multiple "instances" of the same class', () => { + let config = { + content: [{ raw: html`` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + .a { + @apply b; + } + + .b { + @apply uppercase; + } + + .b { + color: red; } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .bop { - color: red; - } - .bar { - background-color: #00f; - } - .foo { - color: red; - background-color: #00f; - position: absolute; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (2 classes)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - @layer utilities { .a, .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .c { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 tag)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - span, - .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - span, - .b, - .c { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 id)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - @layer utilities { - #a, - .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - #a, - .b, - .c { - text-decoration-line: underline; - } - `) - }) - }) - - describe('multiple instances', () => { - it('should be possible to apply multiple "instances" of the same class', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - .a { - @apply b; - } - - .b { - @apply uppercase; - } - - .b { + text-transform: uppercase; color: red; } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should be possible to apply a combination of multiple "instances" of the same class', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - .a { - @apply b; - } - - .b { - @apply uppercase; - color: red; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should generate the same output, even if it was used in a @layer', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - .a { - @apply b; - } - - .b { - @apply uppercase; - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should be possible to apply a combination of multiple "instances" of the same class (defined in a layer)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - .a { - color: red; - @apply b; - color: blue; - } - - .b { - @apply text-green-500; - text-decoration: underline; - } - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .a { - color: red; - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - color: #00f; - text-decoration: underline; - } - .b { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - text-decoration: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .a { - color: red; - color: #22c55e; - color: #00f; - text-decoration: underline; - } - .b { - color: #22c55e; - text-decoration: underline; - } - `) - }) - }) - - it('should properly maintain the order', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - h2 { - @apply text-xl; - @apply lg:text-3xl; - @apply sm:text-2xl; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - h2 { - font-size: 1.25rem; - line-height: 1.75rem; - } - @media (min-width: 1024px) { - h2 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - `) - }) - }) - }) - - it('apply can emit defaults in isolated environments without @tailwind directives', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - - content: [{ raw: html`
` }], - } - - let input = css` - .foo { - @apply focus:rotate-90; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo:focus { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } `) }) }) - it('apply does not emit defaults in isolated environments without optimizeUniversalDefaults', () => { + it('should be possible to apply a combination of multiple "instances" of the same class', () => { let config = { - experimental: { optimizeUniversalDefaults: false }, - content: [{ raw: html`
` }], + content: [{ raw: html`` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` - @tailwind base; + .a { + @apply b; + } - .foo { - @apply focus:rotate-90; + .b { + @apply uppercase; + color: red; } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .foo:focus { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + .a, + .b { + text-transform: uppercase; + color: red; } `) }) }) - it('should work outside of layer', async () => { + it('should generate the same output, even if it was used in a @layer', () => { let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - .input-text { - @apply bg-white; - background-color: red; - } - ` - - let result - result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) - - result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) - }) - - it('should work in layer', async () => { - let config = { - content: [{ raw: html`
` }], + content: [{ raw: html`
` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` @tailwind components; + @layer components { - .input-text { - @apply bg-white; - background-color: red; + .a { + @apply b; + } + + .b { + @apply uppercase; + color: red; } } ` - await run(input, config) - const result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .a, + .b { + text-transform: uppercase; + color: red; + } + `) + }) }) - it('apply partitioning works with media queries', async () => { + it('should be possible to apply a combination of multiple "instances" of the same class (defined in a layer)', () => { let config = { - content: [{ raw: html`` }], + content: [{ raw: html`
` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` - @tailwind base; - @layer base { - html, - body { - @apply text-green-600; - font-size: 1rem; + @tailwind components; + + @layer components { + .a { + color: red; + @apply b; + color: blue; } - @media print { - html, - body { - @apply text-red-600; - font-size: 2rem; - } + .b { + @apply text-green-500; + text-decoration: underline; } } ` - await run(input, config) - const result = await run(input, config) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a { + color: #00f; + --tw-text-opacity: 1; + text-decoration: underline; + } + .b { + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); + text-decoration: underline; + } + `) + }) + }) - stable.expect(result.css).toMatchFormattedCss(css` + it('should properly maintain the order', () => { + let config = { + content: [{ raw: html`` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + h2 { + @apply text-xl; + @apply lg:text-3xl; + @apply sm:text-2xl; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + h2 { + font-size: 1.25rem; + line-height: 1.75rem; + } + @media (min-width: 1024px) { + h2 { + font-size: 1.875rem; + line-height: 2.25rem; + } + } + @media (min-width: 640px) { + h2 { + font-size: 1.5rem; + line-height: 2rem; + } + } + `) + }) + }) +}) + +it('apply can emit defaults in isolated environments without @tailwind directives', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + + content: [{ raw: html`
` }], + } + + let input = css` + .foo { + @apply focus:rotate-90; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo:focus { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +it('apply does not emit defaults in isolated environments without optimizeUniversalDefaults', () => { + let config = { + experimental: { optimizeUniversalDefaults: false }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + + .foo { + @apply focus:rotate-90; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .foo:focus { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +it('should work outside of layer', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + .input-text { + @apply bg-white; + background-color: red; + } + ` + + let result + result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) + + result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) +}) + +it('should work in layer', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind components; + @layer components { + .input-text { + @apply bg-white; + background-color: red; + } + } + ` + + await run(input, config) + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) +}) + +it('apply partitioning works with media queries', async () => { + let config = { + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @layer base { + html, + body { + @apply text-green-600; + font-size: 1rem; + } + + @media print { + html, + body { + @apply text-red-600; + font-size: 2rem; + } + } + } + ` + + await run(input, config) + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + html, + body { + --tw-text-opacity: 1; + color: rgb(22 163 74 / var(--tw-text-opacity)); + font-size: 1rem; + } + @media print { html, body { --tw-text-opacity: 1; - color: rgb(22 163 74 / var(--tw-text-opacity)); - font-size: 1rem; + color: rgb(220 38 38 / var(--tw-text-opacity)); + font-size: 2rem; } - @media print { - html, - body { - --tw-text-opacity: 1; - color: rgb(220 38 38 / var(--tw-text-opacity)); - font-size: 2rem; - } - } - ${defaults} - `) - oxide.expect(result.css).toMatchFormattedCss(css` - html, - body { - color: #16a34a; - font-size: 1rem; - } - @media print { - html, - body { - color: #dc2626; - font-size: 2rem; - } - } - ${defaults} - `) - }) - - it('should be possible to use apply in plugins', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents }) { - addComponents({ - '.a': { - color: 'red', - }, - '.b': { - '@apply a': {}, - color: 'blue', - }, - }) - }, - ], } + ${defaults} + `) +}) - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .a { - color: red; - } - .b { - color: red; - color: #00f; - } - `) - }) - }) +it('should be possible to use apply in plugins', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents }) { + addComponents({ + '.a': { + color: 'red', + }, + '.b': { + '@apply a': {}, + color: 'blue', + }, + }) + }, + ], + } - it('should apply using the updated user CSS when the source has changed', async () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let inputBefore = css` - .foo { - color: green; - } - - .bar { - @apply foo; - } - ` - - let inputAfter = css` - .foo { + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a { color: red; } - - .bar { - @apply foo; - } - ` - - let result = await run(inputBefore, config) - - expect(result.css).toMatchFormattedCss(css` - .foo, - .bar { - color: green; - } - `) - - result = await run(inputAfter, config) - - expect(result.css).toMatchFormattedCss(css` - .foo, - .bar { - color: red; + .b { + color: #00f; } `) }) +}) - it('apply + layer utilities + selector variants (like group) + important selector', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], - plugins: [], +it('should apply using the updated user CSS when the source has changed', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let inputBefore = css` + .foo { + color: green; } - let input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - @apply font-normal group-hover:underline; - } - } - ` + .bar { + @apply foo; + } + ` - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - #myselector :is(.custom-utility) { - font-weight: 400; - } - #myselector :is(.group:hover .custom-utility) { - text-decoration-line: underline; - } - `) - }) - - it('apply + user CSS + selector variants (like group) + important selector (1)', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], - plugins: [], + let inputAfter = css` + .foo { + color: red; } - let input = css` + .bar { + @apply foo; + } + ` + + let result = await run(inputBefore, config) + + expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: green; + } + `) + + result = await run(inputAfter, config) + + expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: red; + } + `) +}) + +it('apply + layer utilities + selector variants (like group) + important selector', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { .custom-utility { @apply font-normal group-hover:underline; } - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .custom-utility { - font-weight: 400; - } - .group:hover .custom-utility { - text-decoration-line: underline; - } - `) - }) - - it('apply + user CSS + selector variants (like group) + important selector (2)', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], - plugins: [], } + ` - let input = css` - #myselector .custom-utility { - @apply font-normal group-hover:underline; - } - ` + let result = await run(input, config) - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - #myselector .custom-utility { - font-weight: 400; - } - .group:hover #myselector .custom-utility { - text-decoration-line: underline; - } - `) - }) - - it('can apply user utilities that start with a dash', async () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + expect(result.css).toMatchFormattedCss(css` + #myselector .custom-utility { + font-weight: 400; } + #myselector :is(.group:hover .custom-utility) { + text-decoration-line: underline; + } + `) +}) - let input = css` - @tailwind utilities; - @layer utilities { - .foo-1 { - margin: 10px; - } - .-foo-1 { - margin: -15px; - } - .new-class { - @apply -foo-1; - } - } - ` +it('apply + user CSS + selector variants (like group) + important selector (1)', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } - let result = await run(input, config) + let input = css` + .custom-utility { + @apply font-normal group-hover:underline; + } + ` - expect(result.css).toMatchFormattedCss(css` + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .custom-utility { + font-weight: 400; + } + .group:hover .custom-utility { + text-decoration-line: underline; + } + `) +}) + +it('apply + user CSS + selector variants (like group) + important selector (2)', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + #myselector .custom-utility { + @apply font-normal group-hover:underline; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + #myselector .custom-utility { + font-weight: 400; + } + .group:hover #myselector .custom-utility { + text-decoration-line: underline; + } + `) +}) + +it('can apply user utilities that start with a dash', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { .foo-1 { margin: 10px; } - .-foo-1, - .new-class { + .-foo-1 { margin: -15px; } - `) - }) - - it('can apply joined classes when using elements', async () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + .new-class { + @apply -foo-1; + } } + ` - let input = css` - .foo.bar { - color: red; - } - .bar.foo { - color: green; - } - header:nth-of-type(odd) { - @apply foo; - } - header::after { - @apply foo; - } - main { - @apply foo bar; - } - footer { - @apply bar; - } - ` + let result = await run(input, config) - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .foo.bar { - color: red; - } - .bar.foo { - color: green; - } - header:nth-of-type(2n + 1).bar { - color: red; - } - header.bar:nth-of-type(2n + 1) { - color: green; - } - header.bar:after, - main.bar, - main.foo, - footer.foo { - color: red; - color: green; - } - `) - }) - - it('should not replace multiple instances of the same class in a single selector', async () => { - // NOTE: This test is non-normative and is not part of the spec of how `@apply` works per-se - // It describes how it currently works because the "correct" way produces a combinatorial explosion - // of selectors that is not easily doable - let config = { - content: [{ raw: html`
` }], - plugins: [], + expect(result.css).toMatchFormattedCss(css` + .foo-1 { + margin: 10px; } - - let input = css` - .foo + .foo { - color: blue; - } - .bar + .bar { - color: fuchsia; - } - header { - @apply foo; - } - main { - @apply foo bar; - } - footer { - @apply bar; - } - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .foo + .foo { - color: #00f; - } - .bar + .bar { - color: #f0f; - } - header + .foo, - main + .foo { - color: #00f; - } - main + .bar, - footer + .bar { - color: #f0f; - } - `) - }) - - it('should maintain the correct selector when applying other utilities', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], + .-foo-1, + .new-class { + margin: -15px; } - - let input = css` - @tailwind utilities; - - .foo:hover.bar .baz { - @apply bg-black; - color: red; - } - - .foo:hover.bar > .baz { - @apply bg-black; - color: red; - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .foo:hover.bar .baz, - .foo:hover.bar > .baz { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .foo:hover.bar .baz, - .foo:hover.bar > .baz { - color: red; - background-color: #000; - } - `) - }) - }) - - it('pseudo elements inside apply are moved outside of :is() or :has()', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - } - - let input = css` - .foo::before { - @apply dark:bg-black/100; - } - - .bar::before { - @apply rtl:dark:bg-black/100; - } - - .baz::before { - @apply rtl:dark:hover:bg-black/100; - } - - .qux::file-selector-button { - @apply rtl:dark:hover:bg-black/100; - } - - .steve::before { - @apply rtl:hover:dark:bg-black/100; - } - - .bob::file-selector-button { - @apply rtl:hover:dark:bg-black/100; - } - - .foo::before { - @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; - } - - .bar::file-selector-button { - @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :is(.dark .foo)::before, - :is([dir='rtl'] :is(.dark .bar))::before, - :is([dir='rtl'] :is(.dark .baz:hover))::before { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .steve):hover):before { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { - background-color: #000; - } - :has([dir='rtl'] .foo:hover):before { - background-color: #000; - } - :has([dir='rtl'] .bar)::file-selector-button:hover { - background-color: #000; - } - `) - }) - }) - - stable.test('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - } - - let input = css` - ::ng-deep .foo .bar { - @apply font-bold; - } - ::v-deep .foo .bar { - @apply font-bold; - } - ::deep .foo .bar { - @apply font-bold; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ::ng-deep .foo .bar { - font-weight: 700; - } - ::v-deep .foo .bar { - font-weight: 700; - } - ::deep .foo .bar { - font-weight: 700; - } - `) - }) - }) - - // 1. `::ng-deep` is deprecated - // 2. `::deep` and `::v-deep` are non-standard - // 3. They all use invalid selector syntax that Lightning CSS does not support - // It may be enough for Oxide to not support it at all - oxide.test.todo('::ng-deep, ::deep, ::v-deep pseudo elements are left alone') + `) +}) + +it('can apply joined classes when using elements', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header:nth-of-type(odd) { + @apply foo; + } + header::after { + @apply foo; + } + main { + @apply foo bar; + } + footer { + @apply bar; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header:nth-of-type(odd).bar { + color: red; + } + header.bar:nth-of-type(odd), + header.bar:after, + main.bar, + main.foo, + footer.foo { + color: green; + } + `) +}) + +it('should not replace multiple instances of the same class in a single selector', async () => { + // NOTE: This test is non-normative and is not part of the spec of how `@apply` works per-se + // It describes how it currently works because the "correct" way produces a combinatorial explosion + // of selectors that is not easily doable + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .foo + .foo { + color: blue; + } + .bar + .bar { + color: fuchsia; + } + header { + @apply foo; + } + main { + @apply foo bar; + } + footer { + @apply bar; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo + .foo { + color: #00f; + } + .bar + .bar { + color: #f0f; + } + header + .foo, + main + .foo { + color: #00f; + } + main + .bar, + footer + .bar { + color: #f0f; + } + `) +}) + +it('should maintain the correct selector when applying other utilities', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + } + + let input = css` + @tailwind utilities; + + .foo:hover.bar .baz { + @apply bg-black; + color: red; + } + + .foo:hover.bar > .baz { + @apply bg-black; + color: red; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo:hover.bar .baz, + .foo:hover.bar > .baz { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + color: red; + } + `) + }) +}) + +it('pseudo elements inside apply are moved outside of :is() or :has()', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + .foo::before { + @apply dark:bg-black/100; + } + + .bar::before { + @apply rtl:dark:bg-black/100; + } + + .baz::before { + @apply rtl:dark:hover:bg-black/100; + } + + .qux::file-selector-button { + @apply rtl:dark:hover:bg-black/100; + } + + .steve::before { + @apply rtl:hover:dark:bg-black/100; + } + + .bob::file-selector-button { + @apply rtl:hover:dark:bg-black/100; + } + + .foo::before { + @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; + } + + .bar::file-selector-button { + @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :is(.dark .foo):before, + :is([dir='rtl'] :is(.dark .bar)):before, + :is([dir='rtl'] :is(.dark .baz:hover)):before { + background-color: #000; + } + :-webkit-any([dir='rtl'] :-webkit-any(.dark .qux))::-webkit-file-upload-button:hover { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .steve):hover):before { + background-color: #000; + } + :-webkit-any([dir='rtl'] :-webkit-any(.dark .bob))::-webkit-file-upload-button:hover { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { + background-color: #000; + } + :has([dir='rtl'] .foo:hover):before { + background-color: #000; + } + :has([dir='rtl'] .bar)::-webkit-file-upload-button:hover { + background-color: #000; + } + :has([dir='rtl'] .bar)::file-selector-button:hover { + background-color: #000; + } + `) + }) +}) + +test('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + ::ng-deep .foo .bar { + @apply font-bold; + } + ::v-deep .foo .bar { + @apply font-bold; + } + ::deep .foo .bar { + @apply font-bold; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ::ng-deep .foo .bar, + ::v-deep .foo .bar, + ::deep .foo .bar { + font-weight: 700; + } + `) + }) }) diff --git a/tests/arbitrary-properties.test.js b/tests/arbitrary-properties.test.js index ce52c1bc7..17f0bcf1f 100644 --- a/tests/arbitrary-properties.test.js +++ b/tests/arbitrary-properties.test.js @@ -1,460 +1,456 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('basic arbitrary properties', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('basic arbitrary properties', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[paint-order\:markers\] { - paint-order: markers; - } - `) - }) - }) - - test('different arbitrary properties are picked up separately', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[bar\:baz\] { - bar: baz; - } - .\[foo\:bar\] { - foo: bar; - } - `) - }) - }) - - test('arbitrary properties with modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { - .dark\:lg\:hover\:\[paint-order\:markers\]:hover { - paint-order: markers; - } - } - } - `) - }) - }) - - test('arbitrary properties are sorted after utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .content-none { - --tw-content: none; - content: var(--tw-content); - } - .\[paint-order\:markers\] { - paint-order: markers; - } - .hover\:pointer-events-none:hover { - pointer-events: none; - } - `) - }) - }) - - test('using CSS variables', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--my-var\:auto\] { - --my-var: auto; - } - `) - }) - }) - - test('using underscores as spaces', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--my-var\:2px_4px\] { - --my-var: 2px 4px; - } - `) - }) - }) - - test('using the important modifier', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\!\[--my-var\:2px_4px\] { - --my-var: 2px 4px !important; - } - `) - }) - }) - - test('colons are allowed in quotes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[content\:\'foo\:bar\'\] { - content: 'foo:bar'; - } - `) - }) - }) - - test('colons are allowed in braces', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[background-image\:url\(http\:\/\/example\.com\/picture\.jpg\)\] { - background-image: url('http://example.com/picture.jpg'); - } - `) - }) - }) - - test('invalid class', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('invalid arbitrary property', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('invalid arbitrary property 2', () => { - let config = { - content: [ - { - raw: html`[0:02]`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('using fractional spacing values inside theme() function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[border\:_calc\(5vw_-_theme\(spacing\[2\.5\]\)\)_double_theme\(\'colors\.fuchsia\.700\'\)\] { - border: calc(5vw - 0.625rem) double #a21caf; - } - `) - }) - }) - - test('using multiple arbitrary props having fractional spacing values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[box-shadow\:_0_calc\(theme\(spacing\[0\.5\]\)_\*_-1\)_theme\(colors\.red\.400\)_inset\] { - box-shadow: inset 0 -0.125rem #f87171; - } - .\[height\:_calc\(100vh_-_theme\(spacing\[2\.5\]\)\)\] { - height: calc(100vh - 0.625rem); - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary properties (without quotes)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--a\:theme\(colors\.blue\.500\)\] { - --a: #3b82f6; - } - .\[color\:var\(--a\)\] { - color: var(--a); - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary properties (with quotes)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--a\:theme\(\'colors\.blue\.500\'\)\] { - --a: #3b82f6; - } - .\[color\:var\(--a\)\] { - color: var(--a); - } - `) - }) - }) - - it('should not generate invalid CSS', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
- `, - - // NOTE: In this case `stillworks:/example` being generated is not ideal - // but it at least doesn't produce invalid CSS when run through prettier - // So we can let it through since it is technically valid - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\[stillworks\:\/example\] { - stillworks: /example; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[paint-order\:markers\] { + paint-order: markers; + } + `) + }) +}) + +test('different arbitrary properties are picked up separately', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[bar\:baz\] { + bar: baz; + } + .\[foo\:bar\] { + foo: bar; + } + `) + }) +}) + +test('arbitrary properties with modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + @media (min-width: 1024px) { + .dark\:lg\:hover\:\[paint-order\:markers\]:hover { + paint-order: markers; + } + } + } + `) + }) +}) + +test('arbitrary properties are sorted after utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .content-none { + --tw-content: none; + content: var(--tw-content); + } + .\[paint-order\:markers\] { + paint-order: markers; + } + .hover\:pointer-events-none:hover { + pointer-events: none; + } + `) + }) +}) + +test('using CSS variables', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--my-var\:auto\] { + --my-var: auto; + } + `) + }) +}) + +test('using underscores as spaces', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--my-var\:2px_4px\] { + --my-var: 2px 4px; + } + `) + }) +}) + +test('using the important modifier', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\!\[--my-var\:2px_4px\] { + --my-var: 2px 4px !important; + } + `) + }) +}) + +test('colons are allowed in quotes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[content\:\'foo\:bar\'\] { + content: 'foo:bar'; + } + `) + }) +}) + +test('colons are allowed in braces', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[background-image\:url\(http\:\/\/example\.com\/picture\.jpg\)\] { + background-image: url('http://example.com/picture.jpg'); + } + `) + }) +}) + +test('invalid class', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('invalid arbitrary property', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('invalid arbitrary property 2', () => { + let config = { + content: [ + { + raw: html`[0:02]`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('using fractional spacing values inside theme() function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[border\:_calc\(5vw_-_theme\(spacing\[2\.5\]\)\)_double_theme\(\'colors\.fuchsia\.700\'\)\] { + border: calc(5vw - 0.625rem) double #a21caf; + } + `) + }) +}) + +test('using multiple arbitrary props having fractional spacing values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[box-shadow\:_0_calc\(theme\(spacing\[0\.5\]\)_\*_-1\)_theme\(colors\.red\.400\)_inset\] { + box-shadow: inset 0 -0.125rem #f87171; + } + .\[height\:_calc\(100vh_-_theme\(spacing\[2\.5\]\)\)\] { + height: calc(100vh - 0.625rem); + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary properties (without quotes)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--a\:theme\(colors\.blue\.500\)\] { + --a: #3b82f6; + } + .\[color\:var\(--a\)\] { + color: var(--a); + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary properties (with quotes)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--a\:theme\(\'colors\.blue\.500\'\)\] { + --a: #3b82f6; + } + .\[color\:var\(--a\)\] { + color: var(--a); + } + `) + }) +}) + +it('should not generate invalid CSS', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+ `, + + // NOTE: In this case `stillworks:/example` being generated is not ideal + // but it at least doesn't produce invalid CSS when run through prettier + // So we can let it through since it is technically valid + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\[stillworks\:\/example\] { + stillworks: /example; + } + `) }) }) diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css deleted file mode 100644 index 97d838d7d..000000000 --- a/tests/arbitrary-values.oxide.test.css +++ /dev/null @@ -1,1070 +0,0 @@ -.inset-\[11px\] { - inset: 11px; -} -.inset-\[var\(--value\)\] { - inset: var(--value); -} -.inset-x-\[11px\] { - left: 11px; - right: 11px; -} -.inset-x-\[var\(--value\)\] { - left: var(--value); - right: var(--value); -} -.inset-y-\[11px\] { - top: 11px; - bottom: 11px; -} -.inset-y-\[var\(--value\)\] { - top: var(--value); - bottom: var(--value); -} -.bottom-\[11px\] { - bottom: 11px; -} -.bottom-\[var\(--value\)\] { - bottom: var(--value); -} -.left-\[11px\] { - left: 11px; -} -.left-\[var\(--value\)\] { - left: var(--value); -} -.right-\[11px\] { - right: 11px; -} -.right-\[var\(--value\)\] { - right: var(--value); -} -.top-\[11px\] { - top: 11px; -} -.top-\[var\(--value\)\] { - top: var(--value); -} -.z-\[123\] { - z-index: 123; -} -.z-\[var\(--value\)\] { - z-index: var(--value); -} -.order-\[4\] { - order: 4; -} -.order-\[var\(--value\)\] { - order: var(--value); -} -.col-\[7\] { - grid-column: 7; -} -.col-start-\[7\] { - grid-column-start: 7; -} -.col-end-\[7\] { - grid-column-end: 7; -} -.row-\[7\] { - grid-row: 7; -} -.row-start-\[7\] { - grid-row-start: 7; -} -.row-end-\[7\] { - grid-row-end: 7; -} -.m-\[7px\] { - margin: 7px; -} -.mx-\[7px\] { - margin-left: 7px; - margin-right: 7px; -} -.my-\[7px\] { - margin-top: 7px; - margin-bottom: 7px; -} -.mb-\[7px\] { - margin-bottom: 7px; -} -.ml-\[7px\] { - margin-left: 7px; -} -.mr-\[7px\] { - margin-right: 7px; -} -.mt-\[7px\] { - margin-top: 7px; -} -.mt-\[clamp\(30px\,100px\)\] { - margin-top: clamp(30px, 100px); -} -.aspect-\[16\/9\] { - aspect-ratio: 16 / 9; -} -.aspect-\[var\(--aspect\)\] { - aspect-ratio: var(--aspect); -} -.h-\[3\.23rem\] { - height: 3.23rem; -} -.h-\[calc\(100\%\+1rem\)\] { - height: calc(100% + 1rem); -} -.h-\[var\(--height\)\] { - height: var(--height); -} -.max-h-\[3\.23rem\] { - max-height: 3.23rem; -} -.max-h-\[calc\(100\%\+1rem\)\] { - max-height: calc(100% + 1rem); -} -.max-h-\[var\(--height\)\] { - max-height: var(--height); -} -.min-h-\[3\.23rem\] { - min-height: 3.23rem; -} -.min-h-\[calc\(100\%\+1rem\)\] { - min-height: calc(100% + 1rem); -} -.min-h-\[var\(--height\)\] { - min-height: var(--height); -} -.w-\[\'\)\(\)\'\] { - width: ')()'; -} -.w-\[\'\]\[\]\'\] { - width: '][]'; -} -.w-\[\'\}\{\}\'\] { - width: '}{}'; -} -.w-\[\(\(\)\)\] { - width: (()); -} -.w-\[\(\)\] { - width: (); -} -.w-\[0\] { - width: 0; -} -.w-\[3\.23rem\] { - width: 3.23rem; -} -.w-\[\[\[\]\]\] { - width: [[]]; -} -.w-\[\[\]\] { - width: []; -} -.w-\[calc\(100\%\+1rem\)\] { - width: calc(100% + 1rem); -} -.w-\[calc\(100\%\/3-1rem\*2\)\] { - width: calc(33.3333% - 2rem); -} -.w-\[calc\(var\(--10-10px\,calc\(-20px-\(-30px--40px\)\)\)-50px\)\] { - width: calc(var(--10-10px, calc(-20px - (-30px - -40px))) - 50px); -} -.w-\[var\(--width\)\] { - width: var(--width); -} -.w-\[var\(--width\,calc\(100\%\+1rem\)\)\] { - width: var(--width, calc(100% + 1rem)); -} -.w-\[\{\{\}\}\] { - width: {{}} -} -.w-\[\{\}\] { - width: {} -} -.min-w-\[3\.23rem\] { - min-width: 3.23rem; -} -.min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: -3.5px; -} -.min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { - min-width: calc(1 - (var(--something) * 0.5)); -} -.min-w-\[calc\(1-var\(--something\)\*0\.5\)\] { - min-width: calc(1 - var(--something) * 0.5); -} -.min-w-\[calc\(100\%\+1rem\)\] { - min-width: calc(100% + 1rem); -} -.min-w-\[var\(--width\)\] { - min-width: var(--width); -} -.max-w-\[3\.23rem\] { - max-width: 3.23rem; -} -.max-w-\[calc\(100\%\+1rem\)\] { - max-width: calc(100% + 1rem); -} -.max-w-\[var\(--width\)\] { - max-width: var(--width); -} -.flex-\[var\(--flex\)\] { - flex: var(--flex); -} -.flex-shrink-\[var\(--shrink\)\], -.shrink-\[var\(--shrink\)\] { - flex-shrink: var(--shrink); -} -.flex-grow-\[var\(--grow\)\], -.grow-\[var\(--grow\)\] { - flex-grow: var(--grow); -} -.basis-\[var\(--basis\)\] { - flex-basis: var(--basis); -} -.origin-\[50px_50px\] { - transform-origin: 50px 50px; -} -.translate-x-\[12\%\] { - --tw-translate-x: 12%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-\[var\(--value\)\] { - --tw-translate-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-\[12\%\] { - --tw-translate-y: 12%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-\[var\(--value\)\] { - --tw-translate-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[1\.5turn\] { - --tw-rotate: 1.5turn; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[2\.3rad\] { - --tw-rotate: 131.78deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[23deg\] { - --tw-rotate: 23deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[401grad\] { - --tw-rotate: 401grad; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-\[3px\] { - --tw-skew-x: 3px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-\[var\(--value\)\] { - --tw-skew-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-\[3px\] { - --tw-skew-y: 3px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-\[var\(--value\)\] { - --tw-skew-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-\[0\.7\] { - --tw-scale-x: 0.7; - --tw-scale-y: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-\[var\(--value\)\] { - --tw-scale-x: var(--value); - --tw-scale-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-x-\[0\.7\] { - --tw-scale-x: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-x-\[var\(--value\)\] { - --tw-scale-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-y-\[0\.7\] { - --tw-scale-y: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-y-\[var\(--value\)\] { - --tw-scale-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.animate-\[pong_1s_cubic-bezier\(0\,0\,0\.2\,1\)_infinite\] { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite pong; -} -.animate-\[var\(--value\)\] { - animation: var(--value); -} -.cursor-\[pointer\] { - cursor: pointer; -} -.cursor-\[url\(\'\.\/path_to_hand\.cur\'\)_2_2\,pointer\] { - cursor: url('./path_to_hand.cur') 2 2, pointer; -} -.cursor-\[url\(hand\.cur\)_2_2\,pointer\] { - cursor: url('hand.cur') 2 2, pointer; -} -.cursor-\[var\(--value\)\] { - cursor: var(--value); -} -.scroll-m-\[7px\] { - scroll-margin: 7px; -} -.scroll-mx-\[7px\] { - scroll-margin-left: 7px; - scroll-margin-right: 7px; -} -.scroll-my-\[7px\] { - scroll-margin-top: 7px; - scroll-margin-bottom: 7px; -} -.scroll-mb-\[7px\] { - scroll-margin-bottom: 7px; -} -.scroll-ml-\[7px\] { - scroll-margin-left: 7px; -} -.scroll-mr-\[7px\] { - scroll-margin-right: 7px; -} -.scroll-mt-\[7px\] { - scroll-margin-top: 7px; -} -.scroll-mt-\[var\(--scroll-margin\)\] { - scroll-margin-top: var(--scroll-margin); -} -.scroll-p-\[7px\] { - scroll-padding: 7px; -} -.scroll-px-\[7px\] { - scroll-padding-left: 7px; - scroll-padding-right: 7px; -} -.scroll-py-\[7px\] { - scroll-padding-top: 7px; - scroll-padding-bottom: 7px; -} -.scroll-pb-\[7px\] { - scroll-padding-bottom: 7px; -} -.scroll-pl-\[7px\] { - scroll-padding-left: 7px; -} -.scroll-pr-\[7px\] { - scroll-padding-right: 7px; -} -.scroll-pt-\[7px\] { - scroll-padding-top: 7px; -} -.scroll-pt-\[var\(--scroll-padding\)\] { - scroll-padding-top: var(--scroll-padding); -} -.list-\[\'\\1f44d\'\] { - list-style-type: '👍'; -} -.list-\[var\(--value\)\] { - list-style-type: var(--value); -} -.list-image-\[url\(\.\/my-image\.png\)\] { - list-style-image: url('./my-image.png'); -} -.list-image-\[var\(--value\)\] { - list-style-image: var(--value); -} -.columns-\[20\] { - columns: 20; -} -.columns-\[var\(--columns\)\] { - columns: var(--columns); -} -.auto-cols-\[minmax\(10px\,auto\)\] { - grid-auto-columns: minmax(10px, auto); -} -.auto-rows-\[minmax\(10px\,auto\)\] { - grid-auto-rows: minmax(10px, auto); -} -.grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; -} -.grid-cols-\[\[linename\]\,1fr\,auto\] { - grid-template-columns: [linename] 1fr auto; -} -.grid-rows-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; -} -.gap-\[20px\] { - gap: 20px; -} -.gap-\[var\(--value\)\] { - gap: var(--value); -} -.gap-x-\[20px\] { - column-gap: 20px; -} -.gap-x-\[var\(--value\)\] { - column-gap: var(--value); -} -.gap-y-\[20px\] { - row-gap: 20px; -} -.gap-y-\[var\(--value\)\] { - row-gap: var(--value); -} -.space-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(20cm * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(20cm * var(--tw-space-x-reverse)); -} -.space-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(calc(20% - 1cm) * var(--tw-space-x-reverse)); -} -.space-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(20cm * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(20cm * var(--tw-space-y-reverse)); -} -.space-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(calc(20% - 1cm) * var(--tw-space-y-reverse)); -} -.divide-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(20cm * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(20cm * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(calc(20% - 1cm) * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(20cm * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(20cm * var(--tw-divide-y-reverse)); -} -.divide-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(calc(20% - 1cm) * var(--tw-divide-y-reverse)); -} -.divide-\[black\] > :not([hidden]) ~ :not([hidden]) { - border-color: #000; -} -.divide-\[var\(--value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--value); -} -.rounded-\[11px\] { - border-radius: 11px; -} -.rounded-b-\[var\(--radius\)\] { - border-bottom-right-radius: var(--radius); - border-bottom-left-radius: var(--radius); -} -.rounded-l-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); - border-bottom-left-radius: var(--radius); -} -.rounded-r-\[var\(--radius\)\] { - border-top-right-radius: var(--radius); - border-bottom-right-radius: var(--radius); -} -.rounded-t-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); - border-top-right-radius: var(--radius); -} -.rounded-bl-\[var\(--radius\)\] { - border-bottom-left-radius: var(--radius); -} -.rounded-br-\[var\(--radius\)\] { - border-bottom-right-radius: var(--radius); -} -.rounded-tl-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); -} -.rounded-tr-\[var\(--radius\)\] { - border-top-right-radius: var(--radius); -} -.border-\[2\.5px\] { - border-width: 2.5px; -} -.border-\[length\:var\(--value\)\] { - border-width: var(--value); -} -.border-b-\[2\.5px\] { - border-bottom-width: 2.5px; -} -.border-b-\[length\:var\(--value\)\] { - border-bottom-width: var(--value); -} -.border-l-\[2\.5px\] { - border-left-width: 2.5px; -} -.border-l-\[length\:var\(--value\)\] { - border-left-width: var(--value); -} -.border-r-\[2\.5px\] { - border-right-width: 2.5px; -} -.border-r-\[length\:var\(--value\)\] { - border-right-width: var(--value); -} -.border-t-\[2\.5px\] { - border-top-width: 2.5px; -} -.border-t-\[length\:var\(--value\)\] { - border-top-width: var(--value); -} -.border-\[\#f00\] { - border-color: red; -} -.border-\[color\:var\(--value\)\] { - border-color: var(--value); -} -.border-\[red_black\] { - border-color: red #000; -} -.border-b-\[\#f00\] { - border-bottom-color: red; -} -.border-b-\[color\:var\(--value\)\] { - border-bottom-color: var(--value); -} -.border-l-\[\#f00\] { - border-left-color: red; -} -.border-l-\[color\:var\(--value\)\] { - border-left-color: var(--value); -} -.border-r-\[\#f00\] { - border-right-color: red; -} -.border-r-\[color\:var\(--value\)\] { - border-right-color: var(--value); -} -.border-t-\[\#f00\] { - border-top-color: red; -} -.border-t-\[color\:var\(--value\)\] { - border-top-color: var(--value); -} -.bg-\[\#0000ffcc\] { - background-color: #00fc; -} -.bg-\[\#0f0\] { - background-color: #0f0; -} -.bg-\[\#0f0_var\(--value\)\] { - background-color: #0f0 var(--value); -} -.bg-\[\#ff0000\] { - background-color: red; -} -.bg-\[color\:var\(--value1\)_var\(--value2\)\] { - background-color: var(--value1) var(--value2); -} -.bg-\[hsl\(0\,100\%\,50\%\)\], -.bg-\[hsl\(0rad\,100\%\,50\%\)\] { - background-color: red; -} -.bg-\[hsla\(0\,100\%\,50\%\,0\.3\)\], -.bg-\[hsla\(0turn\,100\%\,50\%\,0\.3\)\] { - background-color: #ff00004d; -} -.bg-\[rgb\(123\,123\,123\)\] { - background-color: #7b7b7b; -} -.bg-\[rgb\(123\,_456\,_123\)_black\] { - background-color: #7bff7b black; -} -.bg-\[rgb\(123_456_789\)\] { - background-color: #7bffff; -} -.bg-\[rgba\(123\,123\,123\,0\.5\)\] { - background-color: #7b7b7b80; -} -.bg-\[var\(--value\)\,var\(--value\)\] { - background-color: var(--value), var(--value); -} -.bg-\[var\(--value1\)_var\(--value2\)\] { - background-color: var(--value1) var(--value2); -} -.bg-\[image\(\)\,var\(--value\)\] { - background-image: image(), var(--value); -} -.bg-\[image\:var\(--value\)\,var\(--value\)\] { - background-image: var(--value), var(--value); -} -.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { - background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, #ff0, green, #00f); -} -.bg-\[linear-gradient\(\#eee\,\#fff\)\] { - background-image: linear-gradient(#eee, #fff); -} -.bg-\[linear-gradient\(to_left\,rgb\(var\(--green\)\)\,blue\)\] { - background-image: linear-gradient(to left, rgb(var(--green)), blue); -} -.bg-\[url\(\'\/path-to-image\.png\'\)\] { - background-image: url('/path-to-image.png'); -} -.bg-\[url\:var\(--url\)\] { - background-image: var(--url); -} -.from-\[\#da5b66\] { - --tw-gradient-from: #da5b66 var(--tw-gradient-from-position); - --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.from-\[var\(--color\)\] { - --tw-gradient-from: var(--color) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-\[\#da5b66\] { - --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #da5b66 var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.via-\[var\(--color\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--color) var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-\[\#da5b66\] { - --tw-gradient-to: #da5b66 var(--tw-gradient-to-position); -} -.to-\[var\(--color\)\] { - --tw-gradient-to: var(--color) var(--tw-gradient-to-position); -} -.bg-\[length\:200px_100px\] { - background-size: 200px 100px; -} -.bg-\[length\:var\(--value\)\] { - background-size: var(--value); -} -.bg-\[center_top_1rem\] { - background-position: 50% 1rem; -} -.bg-\[position\:200px_100px\] { - background-position: 200px 100px; -} -.bg-\[position\:var\(--value\)\] { - background-position: var(--value); -} -.fill-\[\#da5b66\] { - fill: #da5b66; -} -.fill-\[url\(\#icon-gradient\)\] { - fill: url('#icon-gradient'); -} -.fill-\[var\(--value\)\] { - fill: var(--value); -} -.stroke-\[\#da5b66\] { - stroke: #da5b66; -} -.stroke-\[color\:var\(--value\)\] { - stroke: var(--value); -} -.stroke-\[url\(\#icon-gradient\)\] { - stroke: url('#icon-gradient'); -} -.stroke-\[20px\] { - stroke-width: 20px; -} -.stroke-\[length\:var\(--value\)\] { - stroke-width: var(--value); -} -.object-\[50\%\,50\%\] { - object-position: 50% 50%; -} -.object-\[top\,right\] { - object-position: top right; -} -.object-\[var\(--position\)\] { - object-position: var(--position); -} -.p-\[7px\] { - padding: 7px; -} -.px-\[7px\] { - padding-left: 7px; - padding-right: 7px; -} -.py-\[7px\] { - padding-top: 7px; - padding-bottom: 7px; -} -.pb-\[7px\] { - padding-bottom: 7px; -} -.pl-\[7px\] { - padding-left: 7px; -} -.pr-\[7px\] { - padding-right: 7px; -} -.pt-\[7px\] { - padding-top: 7px; -} -.pt-\[clamp\(30px\,100px\)\] { - padding-top: clamp(30px, 100px); -} -.indent-\[50\%\] { - text-indent: 50%; -} -.indent-\[var\(--indent\)\] { - text-indent: var(--indent); -} -.align-\[10em\] { - vertical-align: 10em; -} -.font-\[\'Gill_Sans\'\] { - font-family: Gill Sans; -} -.font-\[\'Some_Font\'\,\'Some_Other_Font\'\] { - font-family: Some Font, Some Other Font; -} -.font-\[\'Some_Font\'\,sans-serif\] { - font-family: Some Font, sans-serif; -} -.font-\[\'Some_Font\'\,var\(--other-font\)\] { - font-family: 'Some Font', var(--other-font); -} -.font-\[Georgia\,serif\] { - font-family: Georgia, serif; -} -.font-\[family-name\:var\(--value\)\] { - font-family: var(--value); -} -.font-\[sans-serif\,serif\] { - font-family: sans-serif, serif; -} -.font-\[serif\,var\(--value\)\] { - font-family: serif, var(--value); -} -.text-\[0\] { - font-size: 0; -} -.text-\[2\.23rem\] { - font-size: 2.23rem; -} -.text-\[4cqw\] { - font-size: 4cqw; -} -.text-\[length\:var\(--font-size\)\] { - font-size: var(--font-size); -} -.text-\[min\(10vh\,100px\)\] { - font-size: min(10vh, 100px); -} -.font-\[300\] { - font-weight: 300; -} -.font-\[number\:lighter\] { - font-weight: lighter; -} -.font-\[number\:var\(--value\)\] { - font-weight: var(--value); -} -.leading-\[var\(--leading\)\] { - line-height: var(--leading); -} -.tracking-\[var\(--tracking\)\] { - letter-spacing: var(--tracking); -} -.text-\[black\] { - color: #000; -} -.text-\[color\:var\(--color\)\] { - color: var(--color); -} -.text-\[rgb\(123\,123\,123\)\], -.text-\[rgb\(123\,_123\,_123\)\], -.text-\[rgb\(123_123_123\)\] { - color: #7b7b7b; -} -.decoration-\[black\] { - text-decoration-color: #000; -} -.decoration-\[color\:var\(--color\)\] { - text-decoration-color: var(--color); -} -.decoration-\[rgb\(123\,123\,123\)\], -.decoration-\[rgb\(123\,_123\,_123\)\], -.decoration-\[rgb\(123_123_123\)\] { - text-decoration-color: #7b7b7b; -} -.decoration-\[length\:10px\] { - text-decoration-thickness: 10px; -} -.underline-offset-\[10px\] { - text-underline-offset: 10px; -} -.placeholder-\[var\(--placeholder\)\]::placeholder { - color: var(--placeholder); -} -.caret-\[black\] { - caret-color: #000; -} -.caret-\[var\(--value\)\] { - caret-color: var(--value); -} -.accent-\[\#bada55\] { - accent-color: #bada55; -} -.accent-\[var\(--accent-color\)\] { - accent-color: var(--accent-color); -} -.opacity-\[0\.8\] { - opacity: 0.8; -} -.opacity-\[var\(--opacity\)\] { - opacity: var(--opacity); -} -.shadow-\[0px_1px_2px_black\] { - --tw-shadow: 0px 1px 2px black; - --tw-shadow-colored: 0px 1px 2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-\[shadow\:var\(--value\)\] { - --tw-shadow: var(--value); - --tw-shadow-colored: var(--value); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.outline-\[10px\] { - outline-width: 10px; -} -.outline-\[length\:var\(--outline\)\] { - outline-width: var(--outline); -} -.outline-offset-\[10px\] { - outline-offset: 10px; -} -.outline-\[black\] { - outline-color: #000; -} -.outline-\[color\:var\(--outline\)\] { - outline-color: var(--outline); -} -.ring-\[10px\] { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(10px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-\[length\:\(var\(--value\)\)\] { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc((var(--value)) + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-\[\#76ad65\] { - --tw-ring-color: #76ad65; -} -.ring-\[color\:var\(--value\)\] { - --tw-ring-color: var(--value); -} -.ring-offset-\[19rem\] { - --tw-ring-offset-width: 19rem; -} -.ring-offset-\[length\:var\(--value\)\] { - --tw-ring-offset-width: var(--value); -} -.ring-offset-\[\#76ad65\] { - --tw-ring-offset-color: #76ad65; -} -.ring-offset-\[\#ad672f\] { - --tw-ring-offset-color: #ad672f; -} -.ring-offset-\[color\:var\(--value\)\] { - --tw-ring-offset-color: var(--value); -} -.blur-\[15px\] { - --tw-blur: blur(15px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-\[300\%\] { - --tw-brightness: brightness(300%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-\[2\.4\] { - --tw-contrast: contrast(2.4); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-\[0px_1px_2px_black\] { - --tw-drop-shadow: drop-shadow(0px 1px 2px black); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale-\[0\.55\] { - --tw-grayscale: grayscale(0.55); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-\[0\.8turn\] { - --tw-hue-rotate: hue-rotate(0.8turn); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert-\[0\.75\] { - --tw-invert: invert(0.75); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-\[180\%\] { - --tw-saturate: saturate(180%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia-\[0\.2\] { - --tw-sepia: sepia(0.2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.backdrop-blur-\[11px\] { - --tw-backdrop-blur: blur(11px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-\[1\.23\] { - --tw-backdrop-brightness: brightness(1.23); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-\[0\.87\] { - --tw-backdrop-contrast: contrast(0.87); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale-\[0\.42\] { - --tw-backdrop-grayscale: grayscale(0.42); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-\[1\.57rad\] { - --tw-backdrop-hue-rotate: hue-rotate(89.9544deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert-\[0\.66\] { - --tw-backdrop-invert: invert(0.66); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-\[22\%\] { - --tw-backdrop-opacity: opacity(22%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-\[144\%\] { - --tw-backdrop-saturate: saturate(144%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia-\[0\.38\] { - --tw-backdrop-sepia: sepia(0.38); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.transition-\[opacity\,width\] { - transition-property: opacity, width; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-\[var\(--delay\)\] { - transition-delay: var(--delay); -} -.duration-\[2s\] { - transition-duration: 2s; -} -.duration-\[var\(--app-duration\)\] { - transition-duration: var(--app-duration); -} -.will-change-\[top\,left\] { - will-change: top, left; -} -.will-change-\[var\(--will-change\)\] { - will-change: var(--will-change); -} -.content-\[\'\>\'\] { - --tw-content: '>'; - content: var(--tw-content); -} -.content-\[\'hello\'\] { - --tw-content: 'hello'; - content: var(--tw-content); -} -.content-\[attr\(content-before\)\] { - --tw-content: attr(content-before); - content: var(--tw-content); -} -@media (min-width: 1024px) { - .lg\:grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } -} diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index dee766991..ca434ed13 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -134,13 +134,13 @@ min-height: var(--height); } .w-\[\'\)\(\)\'\] { - width: ')()'; + width: ")()"; } .w-\[\'\]\[\]\'\] { - width: '][]'; + width: "][]"; } .w-\[\'\}\{\}\'\] { - width: '}{}'; + width: "}{}"; } .w-\[\(\(\)\)\] { width: (()); @@ -176,16 +176,20 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: {{}} + width: { + { + } + } } .w-\[\{\}\] { - width: {} + width: { + } } .min-w-\[3\.23rem\] { min-width: 3.23rem; } .min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: calc(1 - ((12 - 3) * 0.5)); + min-width: -3.5; } .min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { min-width: calc(1 - (var(--something) * 0.5)); @@ -345,10 +349,10 @@ cursor: pointer; } .cursor-\[url\(\'\.\/path_to_hand\.cur\'\)_2_2\,pointer\] { - cursor: url('./path_to_hand.cur') 2 2, pointer; + cursor: url("./path_to_hand.cur") 2 2, pointer; } .cursor-\[url\(hand\.cur\)_2_2\,pointer\] { - cursor: url('hand.cur') 2 2, pointer; + cursor: url("hand.cur") 2 2, pointer; } .cursor-\[var\(--value\)\] { cursor: var(--value); @@ -406,13 +410,13 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '👍'; + list-style-type: "👍"; } .list-\[var\(--value\)\] { list-style-type: var(--value); } .list-image-\[url\(\.\/my-image\.png\)\] { - list-style-image: url('./my-image.png'); + list-style-image: url("./my-image.png"); } .list-image-\[var\(--value\)\] { list-style-image: var(--value); @@ -681,8 +685,11 @@ .bg-\[linear-gradient\(to_left\,rgb\(var\(--green\)\)\,blue\)\] { background-image: linear-gradient(to left, rgb(var(--green)), blue); } +.bg-\[repeating-conic-gradient\(\#F8F9FA_0\%_25\%\,_white_0\%_50\%\)\] { + background-image: repeating-conic-gradient(#f8f9fa 0% 25%, #fff 0% 50%); +} .bg-\[url\(\'\/path-to-image\.png\'\)\] { - background-image: url('/path-to-image.png'); + background-image: url("/path-to-image.png"); } .bg-\[url\:var\(--url\)\] { background-image: var(--url); @@ -732,7 +739,7 @@ fill: #da5b66; } .fill-\[url\(\#icon-gradient\)\] { - fill: url('#icon-gradient'); + fill: url("#icon-gradient"); } .fill-\[var\(--value\)\] { fill: var(--value); @@ -744,7 +751,7 @@ stroke: var(--value); } .stroke-\[url\(\#icon-gradient\)\] { - stroke: url('#icon-gradient'); + stroke: url("#icon-gradient"); } .stroke-\[20px\] { stroke-width: 20px; @@ -806,7 +813,7 @@ font-family: Some Font, sans-serif; } .font-\[\'Some_Font\'\,var\(--other-font\)\] { - font-family: 'Some Font', var(--other-font); + font-family: "Some Font", var(--other-font); } .font-\[Georgia\,serif\] { font-family: Georgia, serif; @@ -873,6 +880,7 @@ text-decoration-color: #000; } .decoration-\[color\:var\(--color\)\] { + -webkit-text-decoration-color: var(--color); text-decoration-color: var(--color); } .decoration-\[rgb\(123\,123\,123\)\], @@ -1023,54 +1031,90 @@ } .backdrop-blur-\[11px\] { --tw-backdrop-blur: blur(11px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-\[1\.23\] { --tw-backdrop-brightness: brightness(1.23); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-\[0\.87\] { --tw-backdrop-contrast: contrast(0.87); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale-\[0\.42\] { --tw-backdrop-grayscale: grayscale(0.42); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-\[1\.57rad\] { --tw-backdrop-hue-rotate: hue-rotate(89.9544deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert-\[0\.66\] { --tw-backdrop-invert: invert(0.66); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-\[22\%\] { --tw-backdrop-opacity: opacity(22%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-\[144\%\] { --tw-backdrop-saturate: saturate(144%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia-\[0\.38\] { --tw-backdrop-sepia: sepia(0.38); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); @@ -1096,11 +1140,11 @@ will-change: var(--will-change); } .content-\[\'\>\'\] { - --tw-content: '>'; + --tw-content: ">"; content: var(--tw-content); } .content-\[\'hello\'\] { - --tw-content: 'hello'; + --tw-content: "hello"; content: var(--tw-content); } .content-\[attr\(content-before\)\] { @@ -1112,3 +1156,4 @@ grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; } } + diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index 7e65dbf45..5dd6fab84 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -206,6 +206,7 @@
+
diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index 774b4db40..1949e863a 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -1,655 +1,612 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('arbitrary values', () => { - let config = { - content: [path.resolve(__dirname, './arbitrary-values.test.html')], - } +test('arbitrary values', () => { + let config = { + content: [path.resolve(__dirname, './arbitrary-values.test.html')], + } - return run('@tailwind utilities', config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './arbitrary-values.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './arbitrary-values.oxide.test.css'), 'utf8') - ) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './arbitrary-values.test.css'), 'utf8') + ) }) +}) - oxide.test.todo( - 'should only detect classes with arbitrary values that are properly terminated after the arbitrary value' - ) - stable.test( - 'should only detect classes with arbitrary values that are properly terminated after the arbitrary value', - () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], +test('should only detect classes with arbitrary values that are properly terminated after the arbitrary value', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) + }) +}) + +it('should be possible to differentiate between decoration utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .decoration-\[\#ccc\] { + text-decoration-color: #ccc; } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) - } - ) - - it('should be possible to differentiate between decoration utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .decoration-\[\#ccc\] { - text-decoration-color: #ccc; - } - .decoration-\[3px\] { - text-decoration-thickness: 3px; - } - `) - }) + .decoration-\[3px\] { + text-decoration-thickness: 3px; + } + `) }) +}) - it('should support modifiers for arbitrary values that contain the separator', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should support modifiers for arbitrary values that contain the separator', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .hover\:bg-\[url\(\'https\:\/\/github\.com\/tailwindlabs\.png\'\)\]:hover { - background-image: url('https://github.com/tailwindlabs.png'); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .hover\:bg-\[url\(\'https\:\/\/github\.com\/tailwindlabs\.png\'\)\]:hover { + background-image: url('https://github.com/tailwindlabs.png'); + } + `) }) +}) - it('should support arbitrary values for various background utilities', () => { - let config = { - content: [ - { - raw: html` - -
-
+it('should support arbitrary values for various background utilities', () => { + let config = { + content: [ + { + raw: html` + +
+
- -
-
-
-
+ +
+
+
+
- -
-
- `, - }, - ], - } + +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#ff0000\] { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - .bg-\[color\:var\(--bg-color\)\] { - background-color: var(--bg-color); - } - .bg-\[hsl\(var\(--bg-color\)\)\] { - background-color: hsl(var(--bg-color)); - } - .bg-\[rgb\(var\(--bg-color\)\)\] { - background-color: rgb(var(--bg-color)); - } - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .bg-\[url\(\'\/image-1-0\.png\'\)\] { - background-image: url('/image-1-0.png'); - } - .bg-\[url\:var\(--image-url\)\] { - background-image: var(--image-url); - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#ff0000\] { - background-color: red; - } - .bg-\[color\:var\(--bg-color\)\] { - background-color: var(--bg-color); - } - .bg-\[hsl\(var\(--bg-color\)\)\] { - background-color: hsl(var(--bg-color)); - } - .bg-\[rgb\(var\(--bg-color\)\)\] { - background-color: rgb(var(--bg-color)); - } - .bg-red-500 { - background-color: #ef4444; - } - .bg-\[url\(\'\/image-1-0\.png\'\)\] { - background-image: url('/image-1-0.png'); - } - .bg-\[url\:var\(--image-url\)\] { - background-image: var(--image-url); - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#ff0000\] { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + .bg-\[color\:var\(--bg-color\)\] { + background-color: var(--bg-color); + } + .bg-\[hsl\(var\(--bg-color\)\)\] { + background-color: hsl(var(--bg-color)); + } + .bg-\[rgb\(var\(--bg-color\)\)\] { + background-color: rgb(var(--bg-color)); + } + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .bg-\[url\(\'\/image-1-0\.png\'\)\] { + background-image: url('/image-1-0.png'); + } + .bg-\[url\:var\(--image-url\)\] { + background-image: var(--image-url); + } + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + `) }) +}) - it('should not generate any css if an unknown typehint is used', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should not generate any css if an unknown typehint is used', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should handle unknown typehints', () => { - let config = { content: [{ raw: html`
` }] } +it('should handle unknown typehints', () => { + let config = { content: [{ raw: html`
` }] } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[length\:12px\] { - width: 12px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[length\:12px\] { + width: 12px; + } + `) }) +}) - it('should convert _ to spaces', () => { - // Using custom css function here, because otherwise with String.raw, we run - // into an issue with `\2c ` escapes. If we use `\2c ` then JS complains - // about strict mode. But `\\2c ` is not what it expected. - function css(templates) { - return templates.join('') - } +it('should convert _ to spaces', () => { + // Using custom css function here, because otherwise with String.raw, we run + // into an issue with `\2c ` escapes. If we use `\2c ` then JS complains + // about strict mode. But `\\2c ` is not what it expected. + function css(templates) { + return templates.join('') + } - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .col-\\[span_3_\\/_span_8\\] { - grid-column: span 3 / span 8; - } - .row-\\[span_3_\\/_span_8\\] { - grid-row: span 3 / span 8; - } - .m-\\[8px_4px\\] { - margin: 8px 4px; - } - .flex-\\[1_1_100\\%\\] { - flex: 100%; - } - .auto-cols-\\[minmax\\(0\\,_1fr\\)\\] { - grid-auto-columns: minmax(0, 1fr); - } - .grid-cols-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .grid-rows-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { - grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-\\[0px_4px_4px_0px\\] { - border-radius: 0 4px 4px 0; - } - .p-\\[8px_4px\\] { - padding: 8px 4px; - } - .shadow-\\[0px_0px_4px_black\\] { - --tw-shadow: 0px 0px 4px black; - --tw-shadow-colored: 0px 0px 4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .drop-shadow-\\[0px_1px_3px_black\\] { - --tw-drop-shadow: drop-shadow(0px 1px 3px black); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .content-\\[\\'__hello__world__\\'\\] { - --tw-content: ' hello world '; - content: var(--tw-content); - } - .content-\\[___abc____\\] { - --tw-content: abc; - content: var(--tw-content); - } - .content-\\[_hello_world_\\] { - --tw-content: hello world; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .col-\\[span_3_\\/_span_8\\] { + grid-column: span 3 / span 8; + } + .row-\\[span_3_\\/_span_8\\] { + grid-row: span 3 / span 8; + } + .m-\\[8px_4px\\] { + margin: 8px 4px; + } + .flex-\\[1_1_100\\%\\] { + flex: 100%; + } + .auto-cols-\\[minmax\\(0\\,_1fr\\)\\] { + grid-auto-columns: minmax(0, 1fr); + } + .grid-cols-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { + grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .grid-rows-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { + grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .rounded-\\[0px_4px_4px_0px\\] { + border-radius: 0 4px 4px 0; + } + .p-\\[8px_4px\\] { + padding: 8px 4px; + } + .shadow-\\[0px_0px_4px_black\\] { + --tw-shadow: 0px 0px 4px black; + --tw-shadow-colored: 0px 0px 4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .drop-shadow-\\[0px_1px_3px_black\\] { + --tw-drop-shadow: drop-shadow(0px 1px 3px black); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .content-\\[\\'__hello__world__\\'\\] { + --tw-content: ' hello world '; + content: var(--tw-content); + } + .content-\\[___abc____\\] { + --tw-content: abc; + content: var(--tw-content); + } + .content-\\[_hello_world_\\] { + --tw-content: hello world; + content: var(--tw-content); + } + `) }) +}) - it('should not convert escaped underscores with spaces', () => { - let config = { - content: [{ raw: `
` }], - corePlugins: { preflight: false }, - } +it('should not convert escaped underscores with spaces', () => { + let config = { + content: [{ raw: `
` }], + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .content-\[\'snake\\_case\'\] { - --tw-content: 'snake_case'; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .content-\[\'snake\\_case\'\] { + --tw-content: 'snake_case'; + content: var(--tw-content); + } + `) }) +}) - it('should pick the fallback plugin when arbitrary values collide', () => { - let config = { - content: [ - { - raw: html` -
- -
- -
-
- `, - }, - ], - } +it('should pick the fallback plugin when arbitrary values collide', () => { + let config = { + content: [ + { + raw: html` +
+ +
+ +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[var\(--unknown\)\] { - background-color: var(--unknown); - } - .bg-\[200px_100px\] { - background-position: 200px 100px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--unknown\)\] { + background-color: var(--unknown); + } + .bg-\[200px_100px\] { + background-position: 200px 100px; + } + `) }) +}) - it('should pick the fallback plugin when arbitrary values collide and can not be inferred', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should pick the fallback plugin when arbitrary values collide and can not be inferred', () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[var\(--tw-unknown\)\] { - background-color: var(--tw-unknown); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--tw-unknown\)\] { + background-color: var(--tw-unknown); + } + `) }) +}) - it('should warn and not generate if arbitrary values are ambiguous (without fallback)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ matchUtilities }) { - matchUtilities({ foo: (value) => ({ value }) }, { type: ['position'] }) - matchUtilities({ foo: (value) => ({ value }) }, { type: ['size'] }) - }, - ], - } +it('should warn and not generate if arbitrary values are ambiguous (without fallback)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ matchUtilities }) { + matchUtilities({ foo: (value) => ({ value }) }, { type: ['position'] }) + matchUtilities({ foo: (value) => ({ value }) }, { type: ['size'] }) + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should support colons in URLs', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should support colons in URLs', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[url\(\'https\:\/\/www\.spacejam\.com\/1996\/img\/bg_stars\.gif\'\)\] { - background-image: url('https://www.spacejam.com/1996/img/bg_stars.gif'); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[url\(\'https\:\/\/www\.spacejam\.com\/1996\/img\/bg_stars\.gif\'\)\] { + background-image: url('https://www.spacejam.com/1996/img/bg_stars.gif'); + } + `) }) +}) - it('should support unescaped underscores in URLs', () => { - let config = { - content: [ - { raw: html`
` }, - ], - } +it('should support unescaped underscores in URLs', () => { + let config = { + content: [ + { raw: html`
` }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(` + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(` .bg-\\[url\\(\\'brown_potato\\.jpg\\'\\)\\,_url\\(\\'red_tomato\\.png\\'\\)\\] { background-image: url('brown_potato.jpg'), url('red_tomato.png'); } `) - }) - }) - - it('should be possible to read theme values in arbitrary values (without quotes)', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[theme\(spacing\.1\)\] { - width: 0.25rem; - } - .w-\[theme\(spacing\[0\.5\]\)\] { - width: 0.125rem; - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary values (with quotes)', () => { - let config = { - content: [ - { raw: html`
` }, - ], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[theme\(\'spacing\.1\'\)\] { - width: 0.25rem; - } - .w-\[theme\(\'spacing\[0\.5\]\'\)\] { - width: 0.125rem; - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary values (with quotes) when inside calc or similar functions', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[calc\(100\%-theme\(\'spacing\.1\'\)\)\] { - width: calc(100% - 0.25rem); - } - .w-\[calc\(100\%-theme\(\'spacing\[0\.5\]\'\)\)\] { - width: calc(100% - 0.125rem); - } - `) - }) - }) - - it('should not output unparsable arbitrary CSS values', () => { - let config = { - content: [ - { - raw: 'let classes = `w-[${sizes.width}]`', - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(``) - }) - }) - - // Issue: https://github.com/tailwindlabs/tailwindcss/issues/7997 - // `top_right_50%` was a valid percentage before introducing this change - it('should correctly validate each part when checking for `percentage` data types', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[top_right_50\%\] { - background-position: right 50% top; - } - `) - }) - }) - - it('should correctly validate background size', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[auto_auto\,cover\,_contain\,10px\,10px_10\%\] { - background-size: auto, cover, contain, 10px, 10px 10%; - } - `) - }) - }) - - it('should correctly validate combination of percentage and length', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[50\%_10\%\] { - background-position: 50% 10%; - } - .bg-\[50px_10\%\] { - background-position: 50px 10%; - } - .bg-\[50px_10px\] { - background-position: 50px 10px; - } - `) - }) - }) - - it('can explicitly specify type for percentage and length', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[size\:50px_10\%\] { - background-size: 50px 10%; - } - .bg-\[50px_10px\] { - background-position: 50px 10px; - } - .bg-\[position\:50\%_10\%\] { - background-position: 50% 10%; - } - `) - }) - }) - - it('can use CSS variables as arbitrary values without `var()`', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .w-\[--width-var\] { - width: var(--width-var); - } - .bg-\[--color-var\,\#000\] { - background-color: var(--color-var, #000); - } - .bg-\[--color-var\] { - background-color: var(--color-var); - } - .bg-\[length\:--size-var\] { - background-size: var(--size-var); - } - .text-\[length\:--size-var\,12px\] { - font-size: var(--size-var, 12px); - } - `) - }) - }) - - it('can use CSS variables as arbitrary modifiers without `var()`', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/\[--opacity\] { - background-color: rgb(239 68 68 / var(--opacity)); - } - .text-sm\/\[--line-height\] { - font-size: 0.875rem; - line-height: var(--line-height); - } - `) - }) - }) - - it('should support underscores in arbitrary modifiers', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-lg\/\[calc\(50px_\*_2\)\] { - font-size: 1.125rem; - line-height: calc(50px * 2); - } - `) - }) + }) +}) + +it('should be possible to read theme values in arbitrary values (without quotes)', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[theme\(spacing\.1\)\] { + width: 0.25rem; + } + .w-\[theme\(spacing\[0\.5\]\)\] { + width: 0.125rem; + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary values (with quotes)', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[theme\(\'spacing\.1\'\)\] { + width: 0.25rem; + } + .w-\[theme\(\'spacing\[0\.5\]\'\)\] { + width: 0.125rem; + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary values (with quotes) when inside calc or similar functions', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[calc\(100\%-theme\(\'spacing\.1\'\)\)\] { + width: calc(100% - 0.25rem); + } + .w-\[calc\(100\%-theme\(\'spacing\[0\.5\]\'\)\)\] { + width: calc(100% - 0.125rem); + } + `) + }) +}) + +it('should not output unparsable arbitrary CSS values', () => { + let config = { + content: [ + { + raw: 'let classes = `w-[${sizes.width}]`', + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(``) + }) +}) + +// Issue: https://github.com/tailwindlabs/tailwindcss/issues/7997 +// `top_right_50%` was a valid percentage before introducing this change +it('should correctly validate each part when checking for `percentage` data types', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[top_right_50\%\] { + background-position: right 50% top; + } + `) + }) +}) + +it('should correctly validate background size', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[auto_auto\,cover\,_contain\,10px\,10px_10\%\] { + background-size: auto, cover, contain, 10px, 10px 10%; + } + `) + }) +}) + +it('should correctly validate combination of percentage and length', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[50\%_10\%\] { + background-position: 50% 10%; + } + .bg-\[50px_10\%\] { + background-position: 50px 10%; + } + .bg-\[50px_10px\] { + background-position: 50px 10px; + } + `) + }) +}) + +it('can explicitly specify type for percentage and length', () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[size\:50px_10\%\] { + background-size: 50px 10%; + } + .bg-\[50px_10px\] { + background-position: 50px 10px; + } + .bg-\[position\:50\%_10\%\] { + background-position: 50% 10%; + } + `) + }) +}) + +it('can use CSS variables as arbitrary values without `var()`', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .w-\[--width-var\] { + width: var(--width-var); + } + .bg-\[--color-var\,\#000\] { + background-color: var(--color-var, #000); + } + .bg-\[--color-var\] { + background-color: var(--color-var); + } + .bg-\[length\:--size-var\] { + background-size: var(--size-var); + } + .text-\[length\:--size-var\,12px\] { + font-size: var(--size-var, 12px); + } + `) + }) +}) + +it('can use CSS variables as arbitrary modifiers without `var()`', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/\[--opacity\] { + background-color: rgb(239 68 68 / var(--opacity)); + } + .text-sm\/\[--line-height\] { + font-size: 0.875rem; + line-height: var(--line-height); + } + `) + }) +}) + +it('should support underscores in arbitrary modifiers', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-lg\/\[calc\(50px_\*_2\)\] { + font-size: 1.125rem; + line-height: 100px; + } + `) }) }) diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index b210bdc77..ed8e9388c 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -1,377 +1,373 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' +import { flagEnabled } from '../src/featureFlags' -crosscheck(({ stable, oxide }) => { - test('basic arbitrary variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('basic arbitrary variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\>\*\]\:underline > * { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\>\*\]\:underline > * { + text-decoration-line: underline; + } + `) }) +}) - test('spaces in selector (using _)', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('spaces in selector (using _)', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .a.b .\[\.a\.b_\&\]\:underline { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .a.b .\[\.a\.b_\&\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - test('arbitrary variants with modifiers', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('arbitrary variants with modifiers', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { - .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - test('variants without & or an at-rule are ignored', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('arbitrary variants are sorted after other variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .underline { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { @media (min-width: 1024px) { - .lg\:underline { + .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { text-decoration-line: underline; } } - .\[\&\>\*\]\:underline > * { + } + `) + }) +}) + +test('variants without & or an at-rule are ignored', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('arbitrary variants are sorted after other variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .underline { + text-decoration-line: underline; + } + @media (min-width: 1024px) { + .lg\:underline { text-decoration-line: underline; } - `) - }) + } + .\[\&\>\*\]\:underline > * { + text-decoration-line: underline; + } + `) }) +}) - test('using the important modifier', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('using the important modifier', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\>\*\]\:\!underline > * { - text-decoration-line: underline !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\>\*\]\:\!underline > * { + text-decoration-line: underline !important; + } + `) + }) +}) + +test('at-rules', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @supports (what: ever) { + .\[\@supports\(what\:ever\)\]\:underline { + text-decoration-line: underline; } - `) - }) + } + `) }) +}) - test('at-rules', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('nested at-rules', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @supports (what: ever) { - .\[\@supports\(what\:ever\)\]\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - test('nested at-rules', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .\[\@media_screen\{\@media\(hover\:hover\)\}\]\:underline { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - test('at-rules with selector modifications', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { @media (hover: hover) { - .\[\@media\(hover\:hover\)\{\&\:hover\}\]\:underline:hover { + .\[\@media_screen\{\@media\(hover\:hover\)\}\]\:underline { text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('nested at-rules with selector modifications', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('at-rules with selector modifications', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .\[\@media_screen\{\@media\(hover\:hover\)\{\&\:hover\}\}\]\:underline:hover { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (hover: hover) { + .\[\@media\(hover\:hover\)\{\&\:hover\}\]\:underline:hover { + text-decoration-line: underline; + } + } + `) + }) +}) + +test('nested at-rules with selector modifications', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { + @media (hover: hover) { + .\[\@media_screen\{\@media\(hover\:hover\)\{\&\:hover\}\}\]\:underline:hover { + text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('attribute selectors', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('attribute selectors', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-open\]\]\:underline[data-open] { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-open\]\]\:underline[data-open] { + text-decoration-line: underline; + } + `) }) +}) - test('multiple attribute selectors', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]\:underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]\:underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - oxide.test.todo('multiple attribute selectors with custom separator (1)') - stable.test('multiple attribute selectors with custom separator (1)', () => { - let config = { - separator: '__', - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors with custom separator (1)', () => { + let config = { + separator: '__', + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]__underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]__underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - oxide.test.todo('multiple attribute selectors with custom separator (2)') - stable.test('multiple attribute selectors with custom separator (2)', () => { - let config = { - separator: '_@', - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors with custom separator (2)', () => { + let config = { + separator: '_@', + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]_\@underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]_\@underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - test('with @apply', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('with @apply', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = ` + let input = ` @tailwind base; @tailwind components; @tailwind utilities; @@ -381,138 +377,138 @@ crosscheck(({ stable, oxide }) => { } ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .foo:hover { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { + @media (hover: hover) { + .foo:hover { + text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('keeps escaped underscores', () => { - let config = { - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } +test('keeps escaped underscores', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:underline .foo__bar { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:underline .foo__bar { + text-decoration-line: underline; + } + `) }) +}) - test('keeps escaped underscores with multiple arbitrary variants', () => { - let config = { - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } +test('keeps escaped underscores with multiple arbitrary variants', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:\[\&_\.bar\\_\\_baz\]\:underline .bar__baz .foo__bar { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:\[\&_\.bar\\_\\_baz\]\:underline .bar__baz .foo__bar { + text-decoration-line: underline; + } + `) }) +}) - test('keeps escaped underscores in arbitrary variants mixed with normal variants', () => { - let config = { - content: [ - { - raw: ` +test('keeps escaped underscores in arbitrary variants mixed with normal variants', () => { + let config = { + content: [ + { + raw: `
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:hover\:underline:hover .foo__bar, + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:hover\:underline:hover .foo__bar, .hover\:\[\&_\.foo\\_\\_bar\]\:underline .foo__bar:hover { - text-decoration-line: underline; - } - `) - }) + text-decoration-line: underline; + } + `) }) +}) - test('allows attribute variants with quotes', () => { - let config = { - content: [ - { - raw: ` +test('allows attribute variants with quotes', () => { + let config = { + content: [ + { + raw: `
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'], + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'], .\[\&\[data-test\=\'2\'\]\]\:underline[data-test='2'] { - text-decoration-line: underline; - } - `) - }) + text-decoration-line: underline; + } + `) }) +}) - test('classes in arbitrary variants should not be prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: ` +test('classes in arbitrary variants should not be prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: `
should not be red
should be red
@@ -530,731 +526,828 @@ crosscheck(({ stable, oxide }) => {
should be red
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-text-red-400 .foo, - .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, - .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, - .foo .\[\.foo_\&\]\:tw-text-red-400 { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-text-red-400 .foo, - .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, - .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, - .foo .\[\.foo_\&\]\:tw-text-red-400 { - color: #f87171; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&_\.foo\]\:tw-text-red-400 .foo, + .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, + .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, + .foo .\[\.foo_\&\]\:tw-text-red-400 { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); + } + `) }) +}) - test('classes in the same arbitrary variant should not be prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: ` -
should not be red
+test('classes in the same arbitrary variant should not be prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: ` +
should not be red
-
should be red
+
should be red
-
+
should not be red
should be red
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-bg-white .foo { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - .\[\&_\.foo\]\:tw-text-red-400 .foo { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - .foo .\[\.foo_\&\]\:tw-bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - .foo .\[\.foo_\&\]\:tw-text-red-400 { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-bg-white .foo { - background-color: #fff; - } - .\[\&_\.foo\]\:tw-text-red-400 .foo { - color: #f87171; - } - .foo .\[\.foo_\&\]\:tw-bg-white { - background-color: #fff; - } - .foo .\[\.foo_\&\]\:tw-text-red-400 { - color: #f87171; - } - `) - }) - }) - - it('should support aria variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .underline, - .aria-checked\:underline[aria-checked='true'], - .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, - .group[aria-checked='true'] .group-aria-checked\:underline, - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, - .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .aria-checked\:underline[aria-checked='true'], - .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, - .group[aria-checked='true'] .group-aria-checked\:underline, - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, - .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should support data variants', () => { - let config = { - theme: { - data: { - checked: 'ui~="checked"', - }, }, - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .underline, - .data-checked\:underline[data-ui~='checked'], - .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], - .data-\[position\=top\]\:underline[data-position='top'], - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, - .group[data-ui~='checked'] .group-data-checked\:underline, - .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, - .group[data-position='top'] .group-data-\[position\=top\]\:underline, - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, - .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .data-checked\:underline[data-ui~='checked'], - .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], - .data-\[position\=top\]\:underline[data-position='top'], - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, - .group[data-ui~='checked'] .group-data-checked\:underline, - .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, - .group[data-position='top'] .group-data-\[position\=top\]\:underline, - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, - .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&_\.foo\]\:tw-font-bold .foo, + .foo .\[\.foo_\&\]\:tw-font-bold { + font-weight: 700; + } + `) }) +}) - it('should support supports', () => { - let config = { - theme: { - supports: { - grid: 'display: grid', - }, +it('should support aria variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, }, - content: [ - { - raw: html` -
- -
- -
- -
- -
- -
- -
- -
- -
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @supports (display: grid) { - .supports-grid\:underline { - text-decoration-line: underline; - } - .supports-\[display\:grid\]\:grid { - display: grid; - } - } - @supports (foo: bar) and (bar: baz) { - .supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (foo: bar) or (bar: baz) { - .supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (container-type: var(--tw)) { - .supports-\[container-type\]\:underline { - text-decoration-line: underline; - } - } - @supports not (foo: bar) { - .supports-\[not\(foo\:bar\)\]\:underline { - text-decoration-line: underline; - } - } - @supports selector(A > B) { - .supports-\[selector\(A_\>_B\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (transform-origin: 5% 5%) { - .supports-\[transform-origin\:5\%_5\%\]\:underline { - text-decoration-line: underline; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { + text-decoration-line: underline; + } + ` + : css` + .underline, + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { + text-decoration-line: underline; + } + ` + ) }) +}) - it('should be possible to use modifiers and arbitrary groups', () => { - let config = { - content: [ - { - raw: html` -
-
- -
+it('should support data variants', () => { + let config = { + theme: { + data: { + checked: 'ui~="checked"', + }, + }, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - - -
- -
+ let input = css` + @tailwind utilities; + ` - - -
- -
+ return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { + text-decoration-line: underline; + } + ` + : css` + .underline, + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { + text-decoration-line: underline; + } + ` + ) + }) +}) - - -
- -
-
+it('should support supports', () => { + let config = { + theme: { + supports: { + grid: 'display: grid', + }, + }, + content: [ + { + raw: html` +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - -
-
+ let input = css` + @tailwind utilities; + ` -
-
- -
-
- -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group\/foo:hover .group-hover\/foo\:underline, - .group:hover .group-hover\:underline, - .group\/foo:focus .group-\[\&\:focus\]\/foo\:underline, - .group:focus .group-\[\&\:focus\]\:underline, - .group\/foo[data-open] .group-\[\&\[data-open\]\]\/foo\:underline, - .group[data-open] .group-\[\&\[data-open\]\]\:underline, - .group\/foo.in-foo .group-\[\.in-foo\]\/foo\:underline, - .group.in-foo .group-\[\.in-foo\]\:underline, - .in-foo .group\/foo .group-\[\.in-foo_\&\]\/foo\:underline, - .in-foo .group .group-\[\.in-foo_\&\]\:underline, - .group\/foo:hover .group-\[\:hover\]\/foo\:underline, - .group:hover .group-\[\:hover\]\:underline, - .group\/foo[data-open] .group-\[\[data-open\]\]\/foo\:underline, - .group[data-open] .group-\[\[data-open\]\]\:underline { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @supports (display: grid) { + .supports-grid\:underline { text-decoration-line: underline; } - `) - }) + .supports-\[display\:grid\]\:grid { + display: grid; + } + } + @supports (foo: bar) and (bar: baz) { + .supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (foo: bar) or (bar: baz) { + .supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (container-type: var(--tw)) { + .supports-\[container-type\]\:underline { + text-decoration-line: underline; + } + } + @supports not (foo: bar) { + .supports-\[not\(foo\:bar\)\]\:underline { + text-decoration-line: underline; + } + } + @supports selector(A > B) { + .supports-\[selector\(A_\>_B\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (transform-origin: 5% 5%) { + .supports-\[transform-origin\:5\%_5\%\]\:underline { + text-decoration-line: underline; + } + } + `) }) +}) - it('should be possible to use modifiers and arbitrary peers', () => { - let config = { - content: [ - { - raw: html` -
-
+test('has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - -
+ let input = css` + @tailwind utilities; + ` - + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .has-\[\.foo\:hover\]\:block:has(.foo:hover) { + display: block; + } + .has-\[figcaption\]\:inline-block:has(figcaption) { + display: inline-block; + } + .has-\[\[data-active\]\]\:inline:has([data-active]) { + display: inline; + } + .has-\[\.foo\]\:flex:has(.foo) { + display: flex; + } + .has-\[\>_\.potato\]\:table:has(> .potato) { + display: table; + } + .has-\[\+_h2\]\:grid:has(+ h2) { + display: grid; + } + .has-\[\>_h1_\+_h2\]\:contents:has(> h1 + h2) { + display: contents; + } + .has-\[h2\]\:has-\[\.banana\]\:hidden:has(.banana):has(h2) { + display: none; + } + `) + }) +}) + +test('group-has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\:block { + display: block; + } + .group\/two:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\/two\:flex { + display: flex; + } + `) + }) +}) + +test('peer-has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .peer:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\:block { + display: block; + } + .peer\/two:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\/two\:flex { + display: flex; + } + `) + }) +}) + +it('should be possible to use modifiers and arbitrary groups', () => { + let config = { + content: [ + { + raw: html` +
+
+ +
+ + -
+
-
+
- + -
+
-
+
-
+
-
- - -
- -
- -
-
- -
-
- -
-
+
- `, - }, - ], - corePlugins: { preflight: false }, - } - let input = css` - @tailwind utilities; - ` + +
+
- return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .peer\/foo:hover ~ .peer-hover\/foo\:underline, - .peer:hover ~ .peer-hover\:underline, - .peer\/foo:focus ~ .peer-\[\&\:focus\]\/foo\:underline, - .peer:focus ~ .peer-\[\&\:focus\]\:underline, - .peer\/foo[data-open] ~ .peer-\[\&\[data-open\]\]\/foo\:underline, - .peer[data-open] ~ .peer-\[\&\[data-open\]\]\:underline, - .peer\/foo.in-foo ~ .peer-\[\.in-foo\]\/foo\:underline, - .peer.in-foo ~ .peer-\[\.in-foo\]\:underline, - .in-foo .peer\/foo ~ .peer-\[\.in-foo_\&\]\/foo\:underline, - .in-foo .peer ~ .peer-\[\.in-foo_\&\]\:underline, - .peer\/foo:hover ~ .peer-\[\:hover\]\/foo\:underline, - .peer:hover ~ .peer-\[\:hover\]\:underline, - .peer\/foo[data-open] ~ .peer-\[\[data-open\]\]\/foo\:underline, - .peer[data-open] ~ .peer-\[\[data-open\]\]\:underline { - text-decoration-line: underline; - } - `) - }) - }) +
+
- it('Arbitrary variants are ordered alphabetically', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
+
+
+ +
+
- `, - }, - ], - corePlugins: { preflight: false }, - } +
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .\[\&\:\:a\]\:underline::a { - text-decoration-line: underline; - } - .\[\&\:\:b\]\:underline::b { - text-decoration-line: underline; - } - .\[\&\:\:c\]\:underline::c { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group\/foo:hover .group-hover\/foo\:underline, + .group:hover .group-hover\:underline, + .group\/foo:focus .group-\[\&\:focus\]\/foo\:underline, + .group:focus .group-\[\&\:focus\]\:underline, + .group\/foo[data-open] .group-\[\&\[data-open\]\]\/foo\:underline, + .group[data-open] .group-\[\&\[data-open\]\]\:underline, + .group\/foo.in-foo .group-\[\.in-foo\]\/foo\:underline, + .group.in-foo .group-\[\.in-foo\]\:underline, + .in-foo .group\/foo .group-\[\.in-foo_\&\]\/foo\:underline, + .in-foo .group .group-\[\.in-foo_\&\]\:underline, + .group\/foo:hover .group-\[\:hover\]\/foo\:underline, + .group:hover .group-\[\:hover\]\:underline, + .group\/foo[data-open] .group-\[\[data-open\]\]\/foo\:underline, + .group[data-open] .group-\[\[data-open\]\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - it('Arbitrary variants support multiple attribute selectors', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +it('should be possible to use modifiers and arbitrary peers', () => { + let config = { + content: [ + { + raw: html` +
+
- let input = css` - @tailwind utilities; - ` + +
- return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - [data-foo='bar'][data-baz] .\[\[data-foo\=\'bar\'\]\[data-baz\]_\&\]\:underline { - text-decoration-line: underline; - } - `) - }) + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+ +
+ +
+
+ +
+
+ +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .peer\/foo:hover ~ .peer-hover\/foo\:underline, + .peer:hover ~ .peer-hover\:underline, + .peer\/foo:focus ~ .peer-\[\&\:focus\]\/foo\:underline, + .peer:focus ~ .peer-\[\&\:focus\]\:underline, + .peer\/foo[data-open] ~ .peer-\[\&\[data-open\]\]\/foo\:underline, + .peer[data-open] ~ .peer-\[\&\[data-open\]\]\:underline, + .peer\/foo.in-foo ~ .peer-\[\.in-foo\]\/foo\:underline, + .peer.in-foo ~ .peer-\[\.in-foo\]\:underline, + .in-foo .peer\/foo ~ .peer-\[\.in-foo_\&\]\/foo\:underline, + .in-foo .peer ~ .peer-\[\.in-foo_\&\]\:underline, + .peer\/foo:hover ~ .peer-\[\:hover\]\/foo\:underline, + .peer:hover ~ .peer-\[\:hover\]\:underline, + .peer\/foo[data-open] ~ .peer-\[\[data-open\]\]\/foo\:underline, + .peer[data-open] ~ .peer-\[\[data-open\]\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - it('Invalid arbitrary variants selectors should produce nothing instead of failing', () => { - let config = { - content: [ - { - raw: html` +it('Arbitrary variants are ordered alphabetically', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&\:\:a\]\:underline::a { + text-decoration-line: underline; + } + .\[\&\:\:b\]\:underline::b { + text-decoration-line: underline; + } + .\[\&\:\:c\]\:underline::c { + text-decoration-line: underline; + } + `) + }) +}) + +it('Arbitrary variants support multiple attribute selectors', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + [data-foo='bar'][data-baz] .\[\[data-foo\=\'bar\'\]\[data-baz\]_\&\]\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('Invalid arbitrary variants selectors should produce nothing instead of failing', () => { + let config = { + content: [ + { + raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should output responsive variants + stacked variants in the right order', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +it('should output responsive variants + stacked variants in the right order', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1280px) { - .xl\:p-1 { - padding: 0.25rem; - } - } - .\[\&_ul\]\:flex ul { - display: flex; - } - .\[\&_ul\]\:flex-col ul { - flex-direction: column; - } - @media (min-width: 768px) { - .md\:\[\&_ul\]\:flex-row ul { - flex-direction: row; - } - } - `) - }) - }) - - it('it should discard arbitrary variants with multiple selectors', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - { - // escaped commas are a-ok - // This is separate because prettier complains about `\,` in the template string - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .p-1, - .span\,div .hover\:\[\.span\\\,div_\&\]\:p-1:hover, - :is(span, div) .hover\:\[\:is\(span\,div\)_\&\]\:p-1:hover, - div .\[div_\&\]\:p-1, - div .hover\:\[div_\&\]\:p-1:hover { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 1280px) { + .xl\:p-1 { padding: 0.25rem; } - `) - }) + } + .\[\&_ul\]\:flex ul { + display: flex; + } + .\[\&_ul\]\:flex-col ul { + flex-direction: column; + } + @media (min-width: 768px) { + .md\:\[\&_ul\]\:flex-row ul { + flex-direction: row; + } + } + `) }) +}) - it('should sort multiple variant fns with normal variants between them', () => { - /** @type {string[]} */ - let lines = [] +it('it should discard arbitrary variants with multiple selectors', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + { + // escaped commas are a-ok + // This is separate because prettier complains about `\,` in the template string + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - for (let a of [1, 2]) { - for (let b of [2, 1]) { - for (let c of [1, 2]) { - for (let d of [2, 1]) { - for (let e of [1, 2]) { - lines.push(`
`) - } + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .p-1, + .span\,div .hover\:\[\.span\\\,div_\&\]\:p-1:hover, + :is(span, div) .hover\:\[\:is\(span\,div\)_\&\]\:p-1:hover, + div .\[div_\&\]\:p-1, + div .hover\:\[div_\&\]\:p-1:hover { + padding: 0.25rem; + } + `) + }) +}) + +it('should sort multiple variant fns with normal variants between them', () => { + /** @type {string[]} */ + let lines = [] + + for (let a of [1, 2]) { + for (let b of [2, 1]) { + for (let c of [1, 2]) { + for (let d of [2, 1]) { + for (let e of [1, 2]) { + lines.push(`
`) } } } } + } - // Fisher-Yates shuffle - for (let i = lines.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * i) - ;[lines[i], lines[j]] = [lines[j], lines[i]] - } + // Fisher-Yates shuffle + for (let i = lines.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * i) + ;[lines[i], lines[j]] = [lines[j], lines[i]] + } - let config = { - content: [ - { - raw: lines.join('\n'), - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addVariant, matchVariant }) { - addVariant('foo1', "&[data-foo='1']") - addVariant('foo2', "&[data-foo='2']") + let config = { + content: [ + { + raw: lines.join('\n'), + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addVariant, matchVariant }) { + addVariant('foo1', "&[data-foo='1']") + addVariant('foo2', "&[data-foo='2']") - matchVariant('bar', (value) => `&[data-bar='${value}']`, { - sort: (a, b) => b.value - a.value, - }) + matchVariant('bar', (value) => `&[data-bar='${value}']`, { + sort: (a, b) => b.value - a.value, + }) - addVariant('baz1', "&[data-baz='1']") - addVariant('baz2', "&[data-baz='2']") + addVariant('baz1', "&[data-baz='1']") + addVariant('baz2', "&[data-baz='2']") - matchVariant('qux', (value) => `&[data-qux='${value}']`, { - sort: (a, b) => b.value - a.value, - }) + matchVariant('qux', (value) => `&[data-qux='${value}']`, { + sort: (a, b) => b.value - a.value, + }) - addVariant('fred1', "&[data-fred='1']") - addVariant('fred2', "&[data-fred='2']") - }, - ], - } + addVariant('fred1', "&[data-fred='1']") + addVariant('fred2', "&[data-fred='2']") + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { + padding: 0.25rem; + } + `) }) }) diff --git a/tests/basic-usage.oxide.test.css b/tests/basic-usage.oxide.test.css deleted file mode 100644 index 6a01dc045..000000000 --- a/tests/basic-usage.oxide.test.css +++ /dev/null @@ -1,1028 +0,0 @@ -*, -:before, -:after, -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.container { - width: 100%; -} -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} -.sr-only { - width: 1px; - height: 1px; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - margin: -1px; - padding: 0; - position: absolute; - overflow: hidden; -} -.pointer-events-none { - pointer-events: none; -} -.invisible { - visibility: hidden; -} -.collapse { - visibility: collapse; -} -.absolute { - position: absolute; -} -.inset-0 { - inset: 0; -} -.inset-x-2 { - left: 0.5rem; - right: 0.5rem; -} -.inset-y-4 { - top: 1rem; - bottom: 1rem; -} -.bottom-12 { - bottom: 3rem; -} -.left-16 { - left: 4rem; -} -.right-8 { - right: 2rem; -} -.top-6 { - top: 1.5rem; -} -.isolate { - isolation: isolate; -} -.isolation-auto { - isolation: auto; -} -.z-30 { - z-index: 30; -} -.order-2 { - order: 2; -} -.order-last { - order: 9999; -} -.col-span-3 { - grid-column: span 3 / span 3; -} -.col-start-1 { - grid-column-start: 1; -} -.col-end-4 { - grid-column-end: 4; -} -.row-span-2 { - grid-row: span 2 / span 2; -} -.row-start-3 { - grid-row-start: 3; -} -.row-end-5 { - grid-row-end: 5; -} -.float-right { - float: right; -} -.clear-left { - clear: left; -} -.m-4 { - margin: 1rem; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.ml-4 { - margin-left: 1rem; -} -.mr-1 { - margin-right: 0.25rem; -} -.mt-0 { - margin-top: 0; -} -.box-border { - box-sizing: border-box; -} -.inline-grid { - display: inline-grid; -} -.hidden { - display: none; -} -.aspect-square { - aspect-ratio: 1 / 1; -} -.aspect-video { - aspect-ratio: 16 / 9; -} -.h-16 { - height: 4rem; -} -.max-h-screen { - max-height: 100vh; -} -.min-h-0 { - min-height: 0; -} -.w-12 { - width: 3rem; -} -.min-w-min { - min-width: min-content; -} -.max-w-full { - max-width: 100%; -} -.flex-1 { - flex: 1; -} -.flex-shrink { - flex-shrink: 1; -} -.flex-shrink-0 { - flex-shrink: 0; -} -.shrink { - flex-shrink: 1; -} -.shrink-0 { - flex-shrink: 0; -} -.flex-grow { - flex-grow: 1; -} -.flex-grow-0 { - flex-grow: 0; -} -.grow { - flex-grow: 1; -} -.grow-0 { - flex-grow: 0; -} -.basis-7 { - flex-basis: 1.75rem; -} -.basis-auto { - flex-basis: auto; -} -.table-fixed { - table-layout: fixed; -} -.caption-top { - caption-side: top; -} -.caption-bottom { - caption-side: bottom; -} -.border-collapse { - border-collapse: collapse; -} -.border-spacing-4 { - --tw-border-spacing-x: 1rem; - --tw-border-spacing-y: 1rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.border-spacing-x-6 { - --tw-border-spacing-x: 1.5rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.border-spacing-y-8 { - --tw-border-spacing-y: 2rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.origin-top-right { - transform-origin: 100% 0; -} -.-translate-x-3 { - --tw-translate-x: -0.75rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-translate-x-4 { - --tw-translate-x: -1rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-5 { - --tw-translate-x: 1.25rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-6 { - --tw-translate-y: 1.5rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-12 { - --tw-skew-x: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-12 { - --tw-skew-y: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-95 { - --tw-scale-x: 0.95; - --tw-scale-y: 0.95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-scale-x-100 { - --tw-scale-x: -1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-gpu { - transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-none { - transform: none; -} -.animate-none { - animation: none; -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.animate-spin { - animation: 1s linear infinite spin; -} -.cursor-pointer { - cursor: pointer; -} -.touch-pan-x { - --tw-pan-x: pan-x; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pan-y { - --tw-pan-y: pan-y; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pan-up { - --tw-pan-y: pan-up; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pinch-zoom { - --tw-pinch-zoom: pinch-zoom; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-manipulation { - touch-action: manipulation; -} -.select-none { - user-select: none; -} -.resize-none { - resize: none; -} -.snap-x { - scroll-snap-type: x var(--tw-scroll-snap-strictness); -} -.snap-mandatory { - --tw-scroll-snap-strictness: mandatory; -} -.snap-center { - scroll-snap-align: center; -} -.snap-always { - scroll-snap-stop: always; -} -.scroll-mt-6 { - scroll-margin-top: 1.5rem; -} -.scroll-p-6 { - scroll-padding: 1.5rem; -} -.list-inside { - list-style-position: inside; -} -.list-disc { - list-style-type: disc; -} -.list-image-none { - list-style-image: none; -} -.appearance-none { - appearance: none; -} -.columns-1 { - columns: 1; -} -.columns-md { - columns: 28rem; -} -.break-before-page { - break-before: page; -} -.break-inside-avoid-column { - break-inside: avoid-column; -} -.break-after-auto { - break-after: auto; -} -.auto-cols-min { - grid-auto-columns: min-content; -} -.grid-flow-row { - grid-auto-flow: row; -} -.auto-rows-max { - grid-auto-rows: max-content; -} -.grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} -.grid-rows-3 { - grid-template-rows: repeat(3, minmax(0, 1fr)); -} -.flex-row-reverse { - flex-direction: row-reverse; -} -.flex-wrap { - flex-wrap: wrap; -} -.place-content-start { - place-content: start; -} -.place-items-end { - place-items: end; -} -.content-center { - align-content: center; -} -.items-start { - align-items: flex-start; -} -.justify-center { - justify-content: center; -} -.justify-items-end { - justify-items: end; -} -.gap-4 { - gap: 1rem; -} -.gap-x-2 { - column-gap: 0.5rem; -} -.gap-y-3 { - row-gap: 0.75rem; -} -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); -} -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} -.space-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 1; -} -.space-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 1; -} -.divide-x-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(0px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(0px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(2px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(2px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); -} -.divide-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(4px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(4px * var(--tw-divide-y-reverse)); -} -.divide-dotted > :not([hidden]) ~ :not([hidden]) { - border-style: dotted; -} -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - border-color: #e5e7eb; -} -.place-self-center { - place-self: center; -} -.self-end { - align-self: flex-end; -} -.justify-self-start { - justify-self: start; -} -.overflow-hidden { - overflow: hidden; -} -.overscroll-contain { - overscroll-behavior: contain; -} -.truncate { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -.overflow-ellipsis { - text-overflow: ellipsis; -} -.whitespace-nowrap { - white-space: nowrap; -} -.break-words { - overflow-wrap: break-word; -} -.rounded-md { - border-radius: 0.375rem; -} -.border { - border-width: 1px; -} -.border-2 { - border-width: 2px; -} -.border-x-4 { - border-left-width: 4px; - border-right-width: 4px; -} -.border-y-4 { - border-top-width: 4px; - border-bottom-width: 4px; -} -.border-b-4 { - border-bottom-width: 4px; -} -.border-t { - border-top-width: 1px; -} -.border-solid { - border-style: solid; -} -.border-hidden { - border-style: hidden; -} -.border-black { - border-color: #000; -} -.border-x-black { - border-left-color: #000; - border-right-color: #000; -} -.border-y-black { - border-top-color: #000; - border-bottom-color: #000; -} -.border-b-black { - border-bottom-color: #000; -} -.border-l-black { - border-left-color: #000; -} -.border-r-black { - border-right-color: #000; -} -.border-t-black { - border-top-color: #000; -} -.bg-green-500 { - background-color: #22c55e; -} -.bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); -} -.from-red-300 { - --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); - --tw-gradient-to: #fca5a500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-purple-200 { - --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-blue-400 { - --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); -} -.decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.box-decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.box-decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.bg-cover { - background-size: cover; -} -.bg-local { - background-attachment: local; -} -.bg-clip-border { - background-clip: border-box; -} -.bg-top { - background-position: top; -} -.bg-no-repeat { - background-repeat: no-repeat; -} -.bg-origin-border { - background-origin: border-box; -} -.bg-origin-padding { - background-origin: padding-box; -} -.bg-origin-content { - background-origin: content-box; -} -.fill-current { - fill: currentColor; -} -.stroke-current { - stroke: currentColor; -} -.stroke-2 { - stroke-width: 2px; -} -.object-cover { - object-fit: cover; -} -.object-bottom { - object-position: bottom; -} -.p-4 { - padding: 1rem; -} -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pl-4 { - padding-left: 1rem; -} -.pr-2 { - padding-right: 0.5rem; -} -.pt-1 { - padding-top: 0.25rem; -} -.text-center { - text-align: center; -} -.-indent-12 { - text-indent: -3rem; -} -.indent-6 { - text-indent: 1.5rem; -} -.align-middle { - vertical-align: middle; -} -.font-sans { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, - Noto Color Emoji; -} -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} -.font-medium { - font-weight: 500; -} -.uppercase { - text-transform: uppercase; -} -.not-italic { - font-style: normal; -} -.ordinal { - --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.diagonal-fractions { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.leading-5 { - line-height: 1.25rem; -} -.leading-relaxed { - line-height: 1.625; -} -.tracking-tight { - letter-spacing: -0.025em; -} -.text-indigo-500 { - color: #6366f1; -} -.underline { - text-decoration-line: underline; -} -.decoration-red-600 { - text-decoration-color: #dc2626; -} -.decoration-solid { - text-decoration-style: solid; -} -.decoration-1 { - text-decoration-thickness: 1px; -} -.decoration-2 { - text-decoration-thickness: 2px; -} -.underline-offset-1 { - text-underline-offset: 1px; -} -.underline-offset-2 { - text-underline-offset: 2px; -} -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.placeholder-green-300::placeholder { - color: #86efac; -} -.caret-red-600 { - caret-color: #dc2626; -} -.accent-red-600 { - accent-color: #dc2626; -} -.opacity-90 { - opacity: 0.9; -} -.bg-blend-darken { - background-blend-mode: darken; -} -.bg-blend-difference { - background-blend-mode: difference; -} -.mix-blend-multiply { - mix-blend-mode: multiply; -} -.mix-blend-saturation { - mix-blend-mode: saturation; -} -.shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-lg { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-black { - --tw-shadow-color: #000; - --tw-shadow: var(--tw-shadow-colored); -} -.shadow-blue-100\/10 { - --tw-shadow-color: #dbeafe1a; - --tw-shadow: var(--tw-shadow-colored); -} -.shadow-red-500\/25 { - --tw-shadow-color: #ef444440; - --tw-shadow: var(--tw-shadow-colored); -} -.outline-none { - outline-offset: 2px; - outline: 2px solid #0000; -} -.outline { - outline-style: solid; -} -.outline-dashed { - outline-style: dashed; -} -.outline-4 { - outline-width: 4px; -} -.-outline-offset-2 { - outline-offset: -2px; -} -.outline-offset-2 { - outline-offset: 2px; -} -.outline-black { - outline-color: #000; -} -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-4 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-white { - --tw-ring-color: #fff; -} -.ring-offset-2 { - --tw-ring-offset-width: 2px; -} -.ring-offset-blue-300 { - --tw-ring-offset-color: #93c5fd; -} -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px #00000012) drop-shadow(0 2px 2px #0000000f); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter { - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter-none { - filter: none; -} -.backdrop-blur-lg { - --tw-backdrop-blur: blur(16px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-50 { - --tw-backdrop-brightness: brightness(0.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-0 { - --tw-backdrop-contrast: contrast(0); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale { - --tw-backdrop-grayscale: grayscale(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-90 { - --tw-backdrop-hue-rotate: hue-rotate(90deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert { - --tw-backdrop-invert: invert(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-75 { - --tw-backdrop-opacity: opacity(0.75); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-150 { - --tw-backdrop-saturate: saturate(1.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia { - --tw-backdrop-sepia: sepia(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter { - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter-none { - backdrop-filter: none; -} -.transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.transition-all { - transition-property: all; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-300 { - transition-delay: 0.3s; -} -.duration-200 { - transition-duration: 0.2s; -} -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.will-change-scroll { - will-change: scroll-position; -} -.will-change-transform { - will-change: transform; -} -.content-none { - --tw-content: none; - content: var(--tw-content); -} diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 720c783e9..24a414b45 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -1,6 +1,103 @@ *, :before, -:after, +:after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; @@ -79,11 +176,11 @@ } } .sr-only { - width: 1px; - height: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; + width: 1px; + height: 1px; margin: -1px; padding: 0; position: absolute; @@ -196,20 +293,65 @@ display: none; } .aspect-square { - aspect-ratio: 1 / 1; + aspect-ratio: 1; } .aspect-video { aspect-ratio: 16 / 9; } +.h-0 { + height: 0; +} .h-16 { height: 4rem; } +.h-dvh { + height: 100dvh; +} +.h-full { + height: 100%; +} +.h-lvh { + height: 100lvh; +} +.h-screen { + height: 100vh; +} +.h-svh { + height: 100svh; +} +.max-h-0 { + max-height: 0; +} +.max-h-dvh { + max-height: 100dvh; +} +.max-h-full { + max-height: 100%; +} +.max-h-lvh { + max-height: 100lvh; +} .max-h-screen { max-height: 100vh; } +.max-h-svh { + max-height: 100svh; +} .min-h-0 { min-height: 0; } +.min-h-dvh { + min-height: 100dvh; +} +.min-h-full { + min-height: 100%; +} +.min-h-lvh { + min-height: 100lvh; +} +.min-h-svh { + min-height: 100svh; +} .w-12 { width: 3rem; } @@ -382,6 +524,7 @@ touch-action: manipulation; } .select-none { + -webkit-user-select: none; user-select: none; } .resize-none { @@ -415,6 +558,7 @@ list-style-image: none; } .appearance-none { + -webkit-appearance: none; appearance: none; } .columns-1 { @@ -552,6 +696,15 @@ .whitespace-nowrap { white-space: nowrap; } +.text-wrap { + text-wrap: wrap; +} +.text-nowrap { + text-wrap: nowrap; +} +.text-balance { + text-wrap: balance; +} .break-words { overflow-wrap: break-word; } @@ -966,69 +1119,110 @@ } .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-50 { --tw-backdrop-brightness: brightness(0.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-0 { --tw-backdrop-contrast: contrast(0); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale { --tw-backdrop-grayscale: grayscale(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-90 { --tw-backdrop-hue-rotate: hue-rotate(90deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert { --tw-backdrop-invert: invert(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-75 { --tw-backdrop-opacity: opacity(0.75); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-150 { --tw-backdrop-saturate: saturate(1.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia { --tw-backdrop-sepia: sepia(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter-none { + -webkit-backdrop-filter: none; backdrop-filter: none; } .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; + opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 53c2a4418..d32ac43c9 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -1,133 +1,134 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' +import { flagEnabled } from '../src/featureFlags' -crosscheck(({ stable, oxide }) => { - test('basic usage', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
{ backdrop-saturate-150 backdrop-sepia " - >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './basic-usage.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './basic-usage.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './basic-usage.test.css'), 'utf8') + ) }) +}) - test('all plugins are executed that match a candidate', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - green: { - light: 'green', - }, +test('all plugins are executed that match a candidate', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + green: { + light: 'green', }, }, - corePlugins: { preflight: false }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + .bg-green { + /* Empty on purpose */ } + ` - let input = css` - @tailwind utilities; - - .bg-green { - /* Empty on purpose */ + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-green-light { + --tw-bg-opacity: 1; + background-color: rgb(0 128 0 / var(--tw-bg-opacity)); } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-green-light { - --tw-bg-opacity: 1; - background-color: rgb(0 128 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-green-light { - background-color: green; - } - `) - }) + `) }) +}) - test('per-plugin colors with the same key can differ when using a custom colors object', () => { - let config = { - content: [ - { - raw: html` -
This should be green text on red background.
- `, +test('per-plugin colors with the same key can differ when using a custom colors object', () => { + let config = { + content: [ + { + raw: html` +
This should be green text on red background.
+ `, + }, + ], + theme: { + // colors & theme MUST be plain objects + // If they're functions here the test passes regardless + colors: { + theme: { + bg: 'red', + text: 'green', }, - ], - theme: { - // colors & theme MUST be plain objects - // If they're functions here the test passes regardless - colors: { + }, + extend: { + textColor: { theme: { - bg: 'red', - text: 'green', + DEFAULT: 'green', }, }, - extend: { - textColor: { - theme: { - DEFAULT: 'green', - }, - }, - backgroundColor: { - theme: { - DEFAULT: 'red', - }, + backgroundColor: { + theme: { + DEFAULT: 'red', }, }, }, - corePlugins: { preflight: false }, - } + }, + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-theme { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - .text-theme { - --tw-text-opacity: 1; - color: rgb(0 128 0 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-theme { - background-color: red; - } - .text-theme { - color: green; - } - `) - }) - }) - - test('default ring color can be a function', () => { - function color(variable) { - return function ({ opacityVariable, opacityValue }) { - if (opacityValue !== undefined) { - return `rgba(${variable}, ${opacityValue})` - } - if (opacityVariable !== undefined) { - return `rgba(${variable}, var(${opacityVariable}, 1))` - } - return `rgb(${variable})` + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-theme { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); } + .text-theme { + --tw-text-opacity: 1; + color: rgb(0 128 0 / var(--tw-text-opacity)); + } + `) + }) +}) + +test('default ring color can be a function', () => { + function color(variable) { + return function ({ opacityVariable, opacityValue }) { + if (opacityValue !== undefined) { + return `rgba(${variable}, ${opacityValue})` + } + if (opacityVariable !== undefined) { + return `rgba(${variable}, var(${opacityVariable}, 1))` + } + return `rgb(${variable})` } + } - let config = { - content: [ - { - raw: html`
`, - }, - ], + let config = { + content: [ + { + raw: html`
`, + }, + ], - theme: { - extend: { - ringColor: { - DEFAULT: color('var(--red)'), - }, + theme: { + extend: { + ringColor: { + DEFAULT: color('var(--red)'), }, }, - plugins: [], - corePlugins: { preflight: false }, - } + }, + plugins: [], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: 'rgba(var(--red), 0.5)' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgba(var(--red), 0.5)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('falsy config values still work', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - inset: { - 0: 0, - }, +it('falsy config values still work', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + inset: { + 0: 0, }, - plugins: [], - corePlugins: { preflight: false }, - } + }, + plugins: [], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .inset-0 { - inset: 0; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .inset-0 { + inset: 0; + } + `) }) +}) - it('shadows support values without a leading zero', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - boxShadow: { - one: '0.5rem 0.5rem 0.5rem #0005', - two: '.5rem .5rem .5rem #0005', - }, +it('shadows support values without a leading zero', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + boxShadow: { + one: '0.5rem 0.5rem 0.5rem #0005', + two: '.5rem .5rem .5rem #0005', }, - plugins: [], - corePlugins: { preflight: false }, - } + }, + plugins: [], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .shadow-one, - .shadow-two { - --tw-shadow: 0.5rem 0.5rem 0.5rem #0005; - --tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow-one, + .shadow-two { + --tw-shadow: 0.5rem 0.5rem 0.5rem #0005; + --tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) }) +}) - it('can scan extremely long classes without crashing', () => { - let val = 'cols-' + '-a'.repeat(65536) - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('can scan extremely long classes without crashing', () => { + let val = 'cols-' + '-a'.repeat(65536) + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) }) +}) - it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => { - let config = { - content: [{ raw: html`underline focus:*` }], - corePlugins: { preflight: false }, +it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => { + let config = { + content: [{ raw: html`underline focus:*` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + * { + color: red; } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; + .combined, + * { + text-align: center; + } + @layer base { * { - color: red; + color: blue; } + .combined, + * { + color: red; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .combined, + * { + color: red; + } + ${defaults} + .underline { + text-decoration-line: underline; + } + * { + color: red; + } .combined, * { text-align: center; } + `) + }) +}) - @layer base { - * { - color: blue; - } +it('can parse box shadows with variables', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + boxShadow: { + lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', + }, + }, + corePlugins: { preflight: false }, + } - .combined, - * { - color: red; - } + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow-lg { + --tw-shadow: var(--a, 0 35px 60px -15px #000), 0 0 1px #000; + --tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color), + 0 0 1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - * { - color: #00f; - } - .combined, - * { - color: red; - } - ${defaults} - .underline { - text-decoration-line: underline; - } - * { - color: red; - } - .combined, - * { - text-align: center; - } - `) - }) + `) }) +}) - it('can parse box shadows with variables', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - boxShadow: { - lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', - }, - }, - corePlugins: { preflight: false }, - } +it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind components; - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .shadow-lg { - --tw-shadow: var(--a, 0 35px 60px -15px #000), 0 0 1px #000; - --tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color), - 0 0 1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - div:not(.unknown-class) { - color: red; - } + @layer components { + div:not(.unknown-class) { + color: red; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div:not(.unknown-class) { - color: red; - } - `) - }) - }) - - it('supports multiple backgrounds as arbitrary values even if only some are quoted', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, } + ` - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[url\(\'\/images\/one-two-three\.png\'\)\,linear-gradient\(to_right\,_\#eeeeee\,_\#000000\)\] { - background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div:not(.unknown-class) { + color: red; + } + `) }) +}) - it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f680' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: 0.75, - }, +it('supports multiple backgrounds as arbitrary values even if only some are quoted', () => { + let config = { + content: [ + { + raw: html`
`, }, - } + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f6bf' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[url\(\'\/images\/one-two-three\.png\'\)\,linear-gradient\(to_right\,_\#eeeeee\,_\#000000\)\] { + background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000); + } + `) }) +}) - it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f', - }, +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f680' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, }, - } + }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f80' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f6bf' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f00', - }, +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', }, - } + }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f80' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f80' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f67f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: 0.75, - }, +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', }, - } + }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f67f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f80' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f', - }, - }, - } +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f00', - }, +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, }, - } + }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f00' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) }) +}) - it('A bare ring-opacity utility is not supported when not using respectDefaultRingColorOpacity', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: '0.33', - }, +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', }, - } + }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f00' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('A bare ring-opacity utility is not supported when not using respectDefaultRingColorOpacity', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: '0.33', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) + }) +}) + +test('A bare ring-opacity utility is supported when using respectDefaultRingColorOpacity', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: '0.33', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .ring-opacity { + --tw-ring-opacity: 0.33; + } + `) + }) +}) + +it('Ring color utilities are generated when using respectDefaultRingColorOpacity', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .ring-blue-500 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); + } + `) + }) +}) + +test('should not crash when group names contain special characters', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + if (flagEnabled(config, 'oxideParser')) { expect(result.css).toMatchFormattedCss(css``) - }) - }) - - test('A bare ring-opacity utility is supported when using respectDefaultRingColorOpacity', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: '0.33', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .ring-opacity { - --tw-ring-opacity: 0.33; - } - `) - // The opacity plugins are disabled by default in the `oxide` engine - oxide.expect(result.css).toMatchFormattedCss(css``) - }) - }) - - it('Ring color utilities are generated when using respectDefaultRingColorOpacity', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-blue-500 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-blue-500 { - --tw-ring-color: #3b82f6; - } - `) - }) - }) - - oxide.test.todo('should not crash when group names contain special characters') - stable.test('should not crash when group names contain special characters', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { + } else { expect(result.css).toMatchFormattedCss(css` .group\/\$\{id\}:hover .group-hover\/\$\{id\}\:visible { visibility: visible; } `) - }) - }) - - it('should not crash when matching variants where utility classes are doubled up', () => { - let config = { - content: [ - { - raw: '
', - }, - ], } - - let input = css` - @tailwind utilities; - @layer utilities { - .foo.foo { - text-decoration-line: underline; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .hover\:foo:hover.hover\:foo:hover { - text-decoration-line: underline; - } - `) - }) }) +}) - test('detects quoted arbitrary values containing a slash', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], +it('should not crash when matching variants where utility classes are doubled up', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .foo.foo { + text-decoration-line: underline; + } } + ` - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - oxide.expect(result.css).toMatchFormattedCss(css` - .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { - display: none; - } - `) - - stable.expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { - display: none; - } - `) - }) - - test('handled quoted arbitrary values containing escaped spaces', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - oxide.expect(result.css).toMatchFormattedCss(css` - .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { - display: none; - } - `) - - stable.expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { - display: none; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .hover\:foo:hover.hover\:foo:hover { + text-decoration-line: underline; } `) }) }) + +test('detects quoted arbitrary values containing a slash', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { + display: none; + } + ` + : css` + .hidden, + .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { + display: none; + } + ` + ) +}) + +test('handled quoted arbitrary values containing escaped spaces', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { + display: none; + } + ` + : css` + .hidden, + .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { + display: none; + } + ` + ) +}) diff --git a/tests/blocklist.test.js b/tests/blocklist.test.js index 3642aa376..e9915350f 100644 --- a/tests/blocklist.test.js +++ b/tests/blocklist.test.js @@ -1,126 +1,107 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('can block classes matched literally', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - blocklist: ['font', 'uppercase', 'hover:text-sm', 'bg-red-500/50', 'my-custom-class'], +it('can block classes matched literally', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['font', 'uppercase', 'hover:text-sm', 'bg-red-500/50', 'my-custom-class'], + } + + let input = css` + @tailwind utilities; + .my-custom-class { + color: red; } + ` - let input = css` - @tailwind utilities; + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } .my-custom-class { color: red; } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; + @media (min-width: 640px) { + .sm\:hover\:text-sm:hover { + font-size: 0.875rem; + line-height: 1.25rem; } - .my-custom-class { - color: red; - } - @media (min-width: 640px) { - .sm\:hover\:text-sm:hover { - font-size: 0.875rem; - line-height: 1.25rem; - } - } - `) - }) - }) - - it('can block classes inside @layer', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - blocklist: ['my-custom-class'], - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-custom-class { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - `) - }) - }) - - it('blocklists do NOT support regexes', async () => { - let config = { - content: [{ raw: html`
` }], - blocklist: [/^bg-\[[^]+\]$/], - } - - let result = await run('@tailwind utilities', config) - - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#f00d1e\] { - --tw-bg-opacity: 1; - background-color: rgb(240 13 30 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; } `) - - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#f00d1e\] { - background-color: #f00d1e; - } - .font-bold { - font-weight: 700; - } - `) - - expect().toHaveBeenWarnedWith(['blocklist-invalid']) - }) - - it('can block classes generated by the safelist', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [{ pattern: /^bg-red-(400|500)$/ }], - blocklist: ['bg-red-500'], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - background-color: #f87171; - } - .font-bold { - font-weight: 700; - } - `) - }) + }) +}) + +it('can block classes inside @layer', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['my-custom-class'], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-custom-class { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + `) + }) +}) + +it('blocklists do NOT support regexes', async () => { + let config = { + content: [{ raw: html`
` }], + blocklist: [/^bg-\[[^]+\]$/], + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#f00d1e\] { + --tw-bg-opacity: 1; + background-color: rgb(240 13 30 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) + + expect().toHaveBeenWarnedWith(['blocklist-invalid']) +}) + +it('can block classes generated by the safelist', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [{ pattern: /^bg-red-(400|500)$/ }], + blocklist: ['bg-red-500'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-400 { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) }) }) diff --git a/tests/collapse-adjacent-rules.test.js b/tests/collapse-adjacent-rules.test.js index 4dbaab769..69c471686 100644 --- a/tests/collapse-adjacent-rules.test.js +++ b/tests/collapse-adjacent-rules.test.js @@ -1,114 +1,119 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('collapse adjacent rules', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [ - function ({ addVariant }) { - addVariant('foo-bar', '@supports (foo: bar)') - }, - ], +test('collapse adjacent rules', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [ + function ({ addVariant }) { + addVariant('foo-bar', '@supports (foo: bar)') + }, + ], + } + + let input = css` + @tailwind base; + @font-face { + font-family: 'Inter'; + src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); } - - let input = css` - @tailwind base; + @font-face { + font-family: 'Gilroy'; + src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); + } + @page { + margin: 1cm; + } + @tailwind components; + @tailwind utilities; + @layer base { @font-face { - font-family: 'Inter'; + font-family: 'Poppins'; + src: url('/fonts/Poppins.woff2') format('woff2'), url('/fonts/Poppins.woff') format('woff'); + } + @font-face { + font-family: 'Proxima Nova'; + src: url('/fonts/ProximaNova.woff2') format('woff2'), + url('/fonts/ProximaNova.woff') format('woff'); + } + } + .foo, + .bar { + color: black; + } + .foo, + .bar { + font-weight: 700; + } + .some-apply-thing { + @apply foo-bar:md:text-black foo-bar:md:font-bold foo-bar:text-black foo-bar:font-bold md:font-bold md:text-black; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @font-face { + font-family: Poppins; + src: url('/fonts/Poppins.woff2') format('woff2'), url('/fonts/Poppins.woff') format('woff'); + } + @font-face { + font-family: Proxima Nova; + src: url('/fonts/ProximaNova.woff2') format('woff2'), + url('/fonts/ProximaNova.woff') format('woff'); + } + ${defaults} + @font-face { + font-family: Inter; src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); } @font-face { - font-family: 'Gilroy'; + font-family: Gilroy; src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); } @page { margin: 1cm; } - @tailwind components; - @tailwind utilities; - @layer base { - @font-face { - font-family: 'Poppins'; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: 'Proxima Nova'; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - } - .foo, - .bar { - color: black; - } - .foo, - .bar { + .font-bold { font-weight: 700; } - .some-apply-thing { - @apply foo-bar:md:text-black foo-bar:md:font-bold foo-bar:text-black foo-bar:font-bold md:font-bold md:text-black; + .foo, + .bar { + color: #000; + font-weight: 700; } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @font-face { - font-family: Poppins; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: Proxima Nova; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - ${defaults} - @font-face { - font-family: Inter; - src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); - } - @font-face { - font-family: Gilroy; - src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); - } - @page { - margin: 1cm; - } - .font-bold { + @supports (foo: bar) { + .some-apply-thing { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); font-weight: 700; } - .foo, - .bar { - color: #000; + } + @media (min-width: 768px) { + .some-apply-thing { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); font-weight: 700; } - @supports (foo: bar) { - .some-apply-thing { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); - font-weight: 700; - } - } + } + @supports (foo: bar) { @media (min-width: 768px) { .some-apply-thing { --tw-text-opacity: 1; @@ -116,134 +121,49 @@ crosscheck(({ stable, oxide }) => { font-weight: 700; } } - @supports (foo: bar) { - @media (min-width: 768px) { - .some-apply-thing { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); - font-weight: 700; - } - } + } + @media (min-width: 640px) { + .sm\:text-center { + text-align: center; } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 1024px) { - .lg\:text-center { - text-align: center; - } - .lg\:font-bold { - font-weight: 700; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @font-face { - font-family: Poppins; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: Proxima Nova; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - ${defaults} - @font-face { - font-family: Inter; - src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); - } - @font-face { - font-family: Gilroy; - src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); - } - @page { - margin: 1cm; - } - .font-bold { + .sm\:font-bold { font-weight: 700; } - .foo, - .bar { - color: #000; + } + @media (min-width: 768px) { + .md\:text-center { + text-align: center; + } + .md\:font-bold { font-weight: 700; } - @supports (foo: bar) { - .some-apply-thing { - color: #000; - font-weight: 700; - } + } + @media (min-width: 1024px) { + .lg\:text-center { + text-align: center; } - @media (min-width: 768px) { - .some-apply-thing { - color: #000; - font-weight: 700; - } + .lg\:font-bold { + font-weight: 700; } - @supports (foo: bar) { - @media (min-width: 768px) { - .some-apply-thing { - color: #000; - font-weight: 700; - } - } - } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 1024px) { - .lg\:text-center { - text-align: center; - } - .lg\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('duplicate url imports does not break rule collapsing', () => { - let config = { - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } - - let input = css` - @import url('https://example.com'); - @import url('https://example.com'); - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @import 'https://example.com'; - `) - }) + } + `) + }) +}) + +test('duplicate url imports does not break rule collapsing', () => { + let config = { + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @import url('https://example.com'); + @import url('https://example.com'); + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @import 'https://example.com'; + `) }) }) diff --git a/tests/collapse-duplicate-declarations.test.js b/tests/collapse-duplicate-declarations.test.js index 128eb9bef..d36d2e83a 100644 --- a/tests/collapse-duplicate-declarations.test.js +++ b/tests/collapse-duplicate-declarations.test.js @@ -1,177 +1,171 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - it('should collapse duplicate declarations with the same units (px)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } +it('should collapse duplicate declarations with the same units (px)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } - let input = css` - @tailwind utilities; + let input = css` + @tailwind utilities; - @layer utilities { - .example { - height: 100px; - height: 200px; - } + @layer utilities { + .example { + height: 100px; + height: 200px; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 200px; - } - `) - }) - }) - - it('should collapse duplicate declarations with the same units (no unit)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - line-height: 3; - line-height: 2; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 200px; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - line-height: 2; - } - `) - }) - }) - - it('should not collapse duplicate declarations with the different units', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: 100px; - height: 50%; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 100px; - height: 50%; - } - `) - }) - }) - - it('should collapse the duplicate declarations with the same unit, but leave the ones with different units', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: 100px; - height: 50%; - height: 20vh; - height: 200px; - height: 100%; - height: 30vh; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 200px; - height: 100%; - height: 30vh; - } - `) - }) - }) - - it('should collapse the duplicate declarations with the exact same value', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: var(--value); - color: blue; - height: var(--value); - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - color: #00f; - height: var(--value); - } - `) - }) - }) - - it('should work on a real world example', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .h-available { - height: 100%; - height: 100vh; - height: -webkit-fill-available; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .h-available { - height: 100%; - height: 100vh; - height: -webkit-fill-available; - } - `) - }) + `) + }) +}) + +it('should collapse duplicate declarations with the same units (no unit)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + line-height: 3; + line-height: 2; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + line-height: 2; + } + `) + }) +}) + +it('should not collapse duplicate declarations with the different units', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: 100px; + height: 50%; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 50%; + } + `) + }) +}) + +it('should collapse the duplicate declarations with the same unit, but leave the ones with different units', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: 100px; + height: 50%; + height: 20vh; + height: 200px; + height: 100%; + height: 30vh; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 30vh; + } + `) + }) +}) + +it('should collapse the duplicate declarations with the exact same value', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: var(--value); + color: blue; + height: var(--value); + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + color: #00f; + height: var(--value); + } + `) + }) +}) + +it('should work on a real world example', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .h-available { + height: 100%; + height: 100vh; + height: -webkit-fill-available; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .h-available { + height: 100vh; + height: -webkit-fill-available; + } + `) }) }) diff --git a/tests/color-opacity-modifiers.test.js b/tests/color-opacity-modifiers.test.js index 8da4d38c2..a4600a495 100644 --- a/tests/color-opacity-modifiers.test.js +++ b/tests/color-opacity-modifiers.test.js @@ -1,264 +1,234 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('basic color opacity modifier', async () => { - let config = { - content: [{ raw: html`
` }], - } +test('basic color opacity modifier', async () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - background-color: #ef444480; - } - `) - }) - }) - - test('colors with slashes are matched first', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - colors: { - 'red-500/50': '#ff0000', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - background-color: red; - } - `) - }) - }) - - test('arbitrary color opacity modifier', async () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/\[var\(--opacity\)\] { - background-color: rgb(239 68 68 / var(--opacity)); - } - `) - }) - }) - - test('missing alpha generates nothing', async () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('arbitrary color with opacity from scale', async () => { - let config = { - content: [{ raw: 'bg-[wheat]/50' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[wheat\]\/50 { - background-color: #f5deb380; - } - `) - }) - }) - - test('arbitrary color with arbitrary opacity', async () => { - let config = { - content: [{ raw: 'bg-[#bada55]/[0.2]' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[\#bada55\]\/\[0\.2\] { - background-color: #bada5533; - } - `) - }) - }) - - test('undefined theme color with opacity from scale', async () => { - let config = { - content: [{ raw: 'bg-garbage/50' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('values not in the opacity config are ignored', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - opacity: { - 0: '0', - 25: '0.25', - 5: '0.5', - 75: '0.75', - 100: '1', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('function colors are supported', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - blue: ({ opacityValue }) => { - return `rgba(var(--colors-blue), ${opacityValue})` - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-blue\/50 { - background-color: rgba(var(--colors-blue), 0.5); - } - `) - }) - }) - - test('utilities that support any type are supported', async () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - theme: { - extend: { - fill: (theme) => theme('colors'), - }, - }, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .from-red-500\/50 { - --tw-gradient-from: #ef444480 var(--tw-gradient-from-position); - --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .fill-red-500\/25 { - fill: #ef444440; - } - .placeholder-red-500\/75::placeholder { - color: #ef4444bf; - } - `) - }) - }) - - test('opacity modifier in combination with partial custom properties', async () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { - --tw-bg-opacity: 1; - background-color: hsl(123 50% var(--foo) / var(--tw-bg-opacity)); - } - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { - background-color: hsl(123 50% var(--foo) / 0.5); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { - --tw-bg-opacity: 1; - background-color: hsl(123 var(--foo) 50% / var(--tw-bg-opacity)); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { - background-color: hsl(123 var(--foo) 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { - --tw-bg-opacity: 1; - background-color: hsl(var(--foo) 50% 50% / var(--tw-bg-opacity)); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { - background-color: hsl(var(--foo) 50% 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { - background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { - background-color: hsl(123, 50%, var(--foo)); - } - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { - background-color: hsl(123 50% var(--foo) / 0.5); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { - background-color: hsl(123, var(--foo), 50%); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { - background-color: hsl(123 var(--foo) 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { - background-color: hsl(var(--foo), 50%, 50%); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { - background-color: hsl(var(--foo) 50% 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { - background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/50 { + background-color: #ef444480; + } + `) + }) +}) + +test('colors with slashes are matched first', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + colors: { + 'red-500/50': '#ff0000', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/50 { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + `) + }) +}) + +test('arbitrary color opacity modifier', async () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/\[var\(--opacity\)\] { + background-color: rgb(239 68 68 / var(--opacity)); + } + `) + }) +}) + +test('missing alpha generates nothing', async () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('arbitrary color with opacity from scale', async () => { + let config = { + content: [{ raw: 'bg-[wheat]/50' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[wheat\]\/50 { + background-color: #f5deb380; + } + `) + }) +}) + +test('arbitrary color with arbitrary opacity', async () => { + let config = { + content: [{ raw: 'bg-[#bada55]/[0.2]' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#bada55\]\/\[0\.2\] { + background-color: #bada5533; + } + `) + }) +}) + +test('undefined theme color with opacity from scale', async () => { + let config = { + content: [{ raw: 'bg-garbage/50' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('values not in the opacity config are ignored', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + opacity: { + 0: '0', + 25: '0.25', + 5: '0.5', + 75: '0.75', + 100: '1', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('function colors are supported', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + blue: ({ opacityValue }) => { + return `rgba(var(--colors-blue), ${opacityValue})` + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-blue\/50 { + background-color: rgba(var(--colors-blue), 0.5); + } + `) + }) +}) + +test('utilities that support any type are supported', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + theme: { + extend: { + fill: (theme) => theme('colors'), + }, + }, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .from-red-500\/50 { + --tw-gradient-from: #ef444480 var(--tw-gradient-from-position); + --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .fill-red-500\/25 { + fill: #ef444440; + } + .placeholder-red-500\/75::placeholder { + color: #ef4444bf; + } + `) + }) +}) + +test('opacity modifier in combination with partial custom properties', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 50% var(--foo) / var(--tw-bg-opacity)); + } + .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { + background-color: hsl(123 50% var(--foo) / 0.5); + } + .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 var(--foo) 50% / var(--tw-bg-opacity)); + } + .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { + background-color: hsl(123 var(--foo) 50% / 0.5); + } + .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(var(--foo) 50% 50% / var(--tw-bg-opacity)); + } + .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { + background-color: hsl(var(--foo) 50% 50% / 0.5); + } + .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { + background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); + } + `) }) }) diff --git a/tests/color.test.js b/tests/color.test.js index be1d85924..659a2d045 100644 --- a/tests/color.test.js +++ b/tests/color.test.js @@ -1,96 +1,93 @@ import { parseColor, formatColor } from '../src/util/color' -import { crosscheck } from './util/run' -crosscheck(() => { - describe('parseColor', () => { - it.each` - color | output - ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} - ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} - ${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} - ${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} - ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgba', color: ['0', '30', '60'], alpha: '0.5' }} - ${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} - ${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} - ${'rgb(var(--foo), 30, 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} - ${'rgb(0, var(--foo), 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} - ${'rgb(0, 30, var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} - ${'rgb(0, 30, var(--foo), 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} - ${'rgb(var(--foo), 30, var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} - ${'rgb(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'rgb(var(--foo) 30 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} - ${'rgb(0 var(--foo) 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} - ${'rgb(0 30 var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} - ${'rgb(0 30 var(--foo) / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} - ${'rgb(var(--foo) 30 var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} - ${'rgb(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} - ${'hsl(0deg, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} - ${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} - ${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} - ${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0turn', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} - ${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} - ${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} - ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} - ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} - ${'hsl(var(--foo), 30%, 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} - ${'hsl(0, var(--foo), 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} - ${'hsl(0, 30%, var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} - ${'hsl(0, 30%, var(--foo), 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} - ${'hsl(var(--foo), 30%, var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} - ${'hsl(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'hsl(var(--foo) 30% 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} - ${'hsl(0 var(--foo) 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} - ${'hsl(0 30% var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} - ${'hsl(0 30% var(--foo) / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} - ${'hsl(var(--foo) 30% var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} - ${'hsl(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'rgba(var(--foo), 0.1)'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: '0.1' }} - ${'rgba(var(--foo), var(--alpha))'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: 'var(--alpha)' }} - ${'hsla(var(--foo), 0.1)'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: '0.1' }} - ${'hsla(var(--foo), var(--alpha))'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: 'var(--alpha)' }} - ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} - `('should parse "$color" to the correct value', ({ color, output }) => { - expect(parseColor(color)).toEqual(output) - }) - - it.each` - color - ${'var(--my-color)'} - ${'currentColor'} - ${'inherit'} - ${'initial'} - ${'revert'} - ${'unset'} - `('should return `null` for unparseable color "$color"', ({ color }) => { - expect(parseColor(color)).toBe(null) - }) +describe('parseColor', () => { + it.each` + color | output + ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} + ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} + ${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} + ${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} + ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgba', color: ['0', '30', '60'], alpha: '0.5' }} + ${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} + ${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} + ${'rgb(var(--foo), 30, 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} + ${'rgb(0, var(--foo), 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0, 30, var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0, 30, var(--foo), 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo), 30, var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgb(var(--foo) 30 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} + ${'rgb(0 var(--foo) 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0 30 var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0 30 var(--foo) / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo) 30 var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} + ${'hsl(0deg, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} + ${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} + ${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} + ${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} + ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} + ${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} + ${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} + ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} + ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} + ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsl(var(--foo), 30%, 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0, var(--foo), 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0, 30%, var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'hsl(0, 30%, var(--foo), 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} + ${'hsl(var(--foo), 30%, var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} + ${'hsl(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'hsl(var(--foo) 30% 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0 var(--foo) 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0 30% var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'hsl(0 30% var(--foo) / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} + ${'hsl(var(--foo) 30% var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} + ${'hsl(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgba(var(--foo), 0.1)'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: '0.1' }} + ${'rgba(var(--foo), var(--alpha))'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: 'var(--alpha)' }} + ${'hsla(var(--foo), 0.1)'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: '0.1' }} + ${'hsla(var(--foo), var(--alpha))'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: 'var(--alpha)' }} + ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} + `('should parse "$color" to the correct value', ({ color, output }) => { + expect(parseColor(color)).toEqual(output) }) - describe('formatColor', () => { - it.each` - color | output - ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} | ${'rgb(0 0 0)'} - ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} | ${'rgb(0 136 204)'} - ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} | ${'rgb(0 136 204 / 0.6)'} - ${{ mode: 'hsl', color: ['0', '0%', '0%'], alpha: undefined }} | ${'hsl(0 0% 0%)'} - ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: undefined }} | ${'hsl(0 136% 204%)'} - ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: '0.6' }} | ${'hsl(0 136% 204% / 0.6)'} - `('should format the color pieces into a proper "$output"', ({ color, output }) => { - expect(formatColor(color)).toEqual(output) - }) + it.each` + color + ${'var(--my-color)'} + ${'currentColor'} + ${'inherit'} + ${'initial'} + ${'revert'} + ${'unset'} + `('should return `null` for unparseable color "$color"', ({ color }) => { + expect(parseColor(color)).toBe(null) + }) +}) + +describe('formatColor', () => { + it.each` + color | output + ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} | ${'rgb(0 0 0)'} + ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} | ${'rgb(0 136 204)'} + ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} | ${'rgb(0 136 204 / 0.6)'} + ${{ mode: 'hsl', color: ['0', '0%', '0%'], alpha: undefined }} | ${'hsl(0 0% 0%)'} + ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: undefined }} | ${'hsl(0 136% 204%)'} + ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: '0.6' }} | ${'hsl(0 136% 204% / 0.6)'} + `('should format the color pieces into a proper "$output"', ({ color, output }) => { + expect(formatColor(color)).toEqual(output) }) }) diff --git a/tests/combined-selectors.test.js b/tests/combined-selectors.test.js index 51aa0a8ce..b3e8a333f 100644 --- a/tests/combined-selectors.test.js +++ b/tests/combined-selectors.test.js @@ -1,76 +1,74 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should generate the partial selector, if only a partial is used (base layer)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should generate the partial selector, if only a partial is used (base layer)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; + let input = css` + @tailwind base; - @layer base { - :root { - font-weight: bold; - } - - /* --- */ - - :root, - .a { - color: black; - } + @layer base { + :root { + font-weight: bold; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :root { - font-weight: bold; - } - :root, - .a { - color: #000; - } - ${defaults} - `) - }) - }) + /* --- */ - it('should generate the partial selector, if only a partial is used (utilities layer)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - - @layer utilities { - :root { - font-weight: bold; - } - - /* --- */ - - :root, - .a { - color: black; - } + :root, + .a { + color: black; } - ` + } + ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :root { - font-weight: bold; - } - :root, - .a { - color: #000; - } - `) - }) + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :root { + font-weight: bold; + } + :root, + .a { + color: #000; + } + ${defaults} + `) + }) +}) + +it('should generate the partial selector, if only a partial is used (utilities layer)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + @layer utilities { + :root { + font-weight: bold; + } + + /* --- */ + + :root, + .a { + color: black; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :root { + font-weight: bold; + } + :root, + .a { + color: #000; + } + `) }) }) diff --git a/tests/configurePlugins.test.js b/tests/configurePlugins.test.js index 367ab223f..490cddc03 100644 --- a/tests/configurePlugins.test.js +++ b/tests/configurePlugins.test.js @@ -1,28 +1,25 @@ import configurePlugins from '../src/util/configurePlugins' -import { crosscheck } from './util/run' -crosscheck(() => { - test('setting a plugin to false removes it', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] +test('setting a plugin to false removes it', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] - const configuredPlugins = configurePlugins({ display: false }, plugins) + const configuredPlugins = configurePlugins({ display: false }, plugins) - expect(configuredPlugins).toEqual(['fontSize', 'backgroundPosition']) - }) - - test('passing only false removes all plugins', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] - - const configuredPlugins = configurePlugins(false, plugins) - - expect(configuredPlugins).toEqual([]) - }) - - test('passing an array safelists plugins', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] - - const configuredPlugins = configurePlugins(['display'], plugins) - - expect(configuredPlugins).toEqual(['display']) - }) + expect(configuredPlugins).toEqual(['fontSize', 'backgroundPosition']) +}) + +test('passing only false removes all plugins', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] + + const configuredPlugins = configurePlugins(false, plugins) + + expect(configuredPlugins).toEqual([]) +}) + +test('passing an array safelists plugins', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] + + const configuredPlugins = configurePlugins(['display'], plugins) + + expect(configuredPlugins).toEqual(['display']) }) diff --git a/tests/containerPlugin.test.js b/tests/containerPlugin.test.js index 428a807d0..4b334e90c 100644 --- a/tests/containerPlugin.test.js +++ b/tests/containerPlugin.test.js @@ -1,347 +1,345 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({}) => { - test('options are not required', () => { - let config = { content: [{ raw: html`
` }] } +test('options are not required', () => { + let config = { content: [{ raw: html`
` }] } - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('screens can be passed explicitly', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('screens are ordered ascending by min-width', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['500px', '400px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1024px) { .container { - width: 100%; + max-width: 1024px; } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('screens are deduplicated by min-width', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: { - sm: '576px', - md: '768px', - 'sm-only': { min: '576px', max: '767px' }, - }, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1280px) { .container { - width: 100%; + max-width: 1280px; } - @media (min-width: 576px) { - .container { - max-width: 576px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - `) - }) - }) - - test('the container can be centered by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - center: true, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1536px) { .container { - width: 100%; - margin-left: auto; - margin-right: auto; + max-width: 1536px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('horizontal padding can be included by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - padding: '2rem', - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - padding-left: 2rem; - padding-right: 2rem; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('responsive horizontal padding can be included by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - screens: { - sm: '576px', - md: { min: '768px' }, - lg: { 'min-width': '992px' }, - xl: { min: '1200px', max: '1600px' }, - }, - container: { - padding: { - DEFAULT: '1rem', - sm: '2rem', - lg: '4rem', - xl: '5rem', - }, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - padding-left: 1rem; - padding-right: 1rem; - } - @media (min-width: 576px) { - .container { - max-width: 576px; - padding-left: 2rem; - padding-right: 2rem; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 992px) { - .container { - max-width: 992px; - padding-left: 4rem; - padding-right: 4rem; - } - } - @media (min-width: 1200px) { - .container { - max-width: 1200px; - padding-left: 5rem; - padding-right: 5rem; - } - } - `) - }) - }) - - test('setting all options at once', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - center: true, - padding: '2rem', - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - margin-left: auto; - margin-right: auto; - padding-left: 2rem; - padding-right: 2rem; - } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('container can use variants', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1024px) { - .lg\:hover\:container:hover { - width: 100%; - } - @media (min-width: 400px) { - .lg\:hover\:container:hover { - max-width: 400px; - } - } - @media (min-width: 500px) { - .lg\:hover\:container:hover { - max-width: 500px; - } - } - } - `) - }) + } + `) + }) +}) + +test('screens can be passed explicitly', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('screens are ordered ascending by min-width', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['500px', '400px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('screens are deduplicated by min-width', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: { + sm: '576px', + md: '768px', + 'sm-only': { min: '576px', max: '767px' }, + }, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 576px) { + .container { + max-width: 576px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + `) + }) +}) + +test('the container can be centered by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + center: true, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + margin-left: auto; + margin-right: auto; + } + @media (min-width: 640px) { + .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + `) + }) +}) + +test('horizontal padding can be included by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + padding: '2rem', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + padding-left: 2rem; + padding-right: 2rem; + } + @media (min-width: 640px) { + .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + `) + }) +}) + +test('responsive horizontal padding can be included by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + sm: '576px', + md: { min: '768px' }, + lg: { 'min-width': '992px' }, + xl: { min: '1200px', max: '1600px' }, + }, + container: { + padding: { + DEFAULT: '1rem', + sm: '2rem', + lg: '4rem', + xl: '5rem', + }, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + padding-left: 1rem; + padding-right: 1rem; + } + @media (min-width: 576px) { + .container { + max-width: 576px; + padding-left: 2rem; + padding-right: 2rem; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 992px) { + .container { + max-width: 992px; + padding-left: 4rem; + padding-right: 4rem; + } + } + @media (min-width: 1200px) { + .container { + max-width: 1200px; + padding-left: 5rem; + padding-right: 5rem; + } + } + `) + }) +}) + +test('setting all options at once', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + center: true, + padding: '2rem', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + margin-left: auto; + margin-right: auto; + padding-left: 2rem; + padding-right: 2rem; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('container can use variants', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 1024px) { + .lg\:hover\:container:hover { + width: 100%; + } + @media (min-width: 400px) { + .lg\:hover\:container:hover { + max-width: 400px; + } + } + @media (min-width: 500px) { + .lg\:hover\:container:hover { + max-width: 500px; + } + } + } + `) }) }) diff --git a/tests/context-reuse.test.js b/tests/context-reuse.test.js index 4ead43fd4..7cd006cde 100644 --- a/tests/context-reuse.test.js +++ b/tests/context-reuse.test.js @@ -1,4 +1,4 @@ -import { crosscheck, css } from './util/run' +import { css } from './util/run' const fs = require('fs') const path = require('path') @@ -7,126 +7,122 @@ const tailwind = require('../src/index.js') const sharedState = require('../src/lib/sharedState.js') const configPath = path.resolve(__dirname, './context-reuse.tailwind.config.js') -crosscheck(({ stable, oxide }) => { - function run(input, config = {}, from = null) { - let { currentTestName } = expect.getState() +function run(input, config = {}, from = null) { + let { currentTestName } = expect.getState() - from = `${path.resolve(__filename)}?test=${currentTestName}&${from}` + from = `${path.resolve(__filename)}?test=${currentTestName}&${from}` - return postcss(tailwind(config)).process(input, { from }) + return postcss(tailwind(config)).process(input, { from }) +} + +beforeEach(async () => { + let config = { + content: [path.resolve(__dirname, './context-reuse.test.html')], + corePlugins: { preflight: false }, } - beforeEach(async () => { - let config = { - content: [path.resolve(__dirname, './context-reuse.test.html')], - corePlugins: { preflight: false }, + await fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) +}) + +afterEach(async () => { + await fs.promises.unlink(configPath) +}) + +test('re-uses the context across multiple files with the same config', async () => { + let results = [ + await run(`@tailwind utilities;`, configPath, `id=1`), + + // Using @apply directives should still re-use the context + // They depend on the config but do not the other way around + await run(`body { @apply bg-blue-400; }`, configPath, `id=2`), + await run(`body { @apply text-red-400; }`, configPath, `id=3`), + await run(`body { @apply mb-4; }`, configPath, `id=4`), + ] + + let dependencies = results.map((result) => { + return result.messages + .filter((message) => message.type === 'dependency') + .map((message) => message.file) + }) + + // The content files don't have any utilities in them so this should be empty + expect(results[0].css).toMatchFormattedCss(css``) + + // However, @apply is being used so we want to verify that they're being inlined into the CSS rules + expect(results[1].css).toMatchFormattedCss(css` + body { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } + `) - await fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) - }) + expect(results[2].css).toMatchFormattedCss(css` + body { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); + } + `) - afterEach(async () => { - await fs.promises.unlink(configPath) - }) + expect(results[3].css).toMatchFormattedCss(css` + body { + margin-bottom: 1rem; + } + `) - oxide.test.todo('re-uses the context across multiple files with the same config') - stable.test('re-uses the context across multiple files with the same config', async () => { - let results = [ - await run(`@tailwind utilities;`, configPath, `id=1`), + // Files with @tailwind directives depends on the PostCSS tree, config, AND any content files + expect(dependencies[0]).toEqual([ + path.resolve(__dirname, 'context-reuse.test.html'), + path.resolve(__dirname, 'context-reuse.tailwind.config.js'), + ]) - // Using @apply directives should still re-use the context - // They depend on the config but do not the other way around - await run(`body { @apply bg-blue-400; }`, configPath, `id=2`), - await run(`body { @apply text-red-400; }`, configPath, `id=3`), - await run(`body { @apply mb-4; }`, configPath, `id=4`), - ] + // @apply depends only on the containing PostCSS tree *and* the config file but no content files + // as they cannot affect the outcome of the @apply directives + expect(dependencies[1]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - let dependencies = results.map((result) => { - return result.messages - .filter((message) => message.type === 'dependency') - .map((message) => message.file) - }) + expect(dependencies[2]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - // The content files don't have any utilities in them so this should be empty - expect(results[0].css).toMatchFormattedCss(css``) + expect(dependencies[3]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - // However, @apply is being used so we want to verify that they're being inlined into the CSS rules - expect(results[1].css).toMatchFormattedCss(css` - body { - --tw-bg-opacity: 1; - background-color: rgb(96 165 250 / var(--tw-bg-opacity)); - } - `) + // And none of this should have resulted in multiple contexts being created + expect(sharedState.contextSourcesMap.size).toBe(1) +}) - expect(results[2].css).toMatchFormattedCss(css` - body { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) +test('updates layers when any CSS containing @tailwind directives changes', async () => { + let result - expect(results[3].css).toMatchFormattedCss(css` - body { - margin-bottom: 1rem; - } - `) - - // Files with @tailwind directives depends on the PostCSS tree, config, AND any content files - expect(dependencies[0]).toEqual([ - path.resolve(__dirname, 'context-reuse.test.html'), - path.resolve(__dirname, 'context-reuse.tailwind.config.js'), - ]) - - // @apply depends only on the containing PostCSS tree *and* the config file but no content files - // as they cannot affect the outcome of the @apply directives - expect(dependencies[1]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - expect(dependencies[2]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - expect(dependencies[3]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - // And none of this should have resulted in multiple contexts being created - expect(sharedState.contextSourcesMap.size).toBe(1) - }) - - oxide.test.todo('updates layers when any CSS containing @tailwind directives changes') - stable.test('updates layers when any CSS containing @tailwind directives changes', async () => { - let result - - // Compile the initial version once - let input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - color: orange; - } - } - ` - - result = await run(input, configPath, `id=1`) - - expect(result.css).toMatchFormattedCss(css` - .only\:custom-utility:only-child { + // Compile the initial version once + let input = css` + @tailwind utilities; + @layer utilities { + .custom-utility { color: orange; } - `) + } + ` - // Save the file with a change - input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - color: blue; - } + result = await run(input, configPath, `id=1`) + + expect(result.css).toMatchFormattedCss(css` + .only\:custom-utility:only-child { + color: orange; + } + `) + + // Save the file with a change + input = css` + @tailwind utilities; + @layer utilities { + .custom-utility { + color: blue; } - ` + } + ` - result = await run(input, configPath, `id=1`) + result = await run(input, configPath, `id=1`) - expect(result.css).toMatchFormattedCss(css` - .only\:custom-utility:only-child { - color: #00f; - } - `) - }) + expect(result.css).toMatchFormattedCss(css` + .only\:custom-utility:only-child { + color: #00f; + } + `) }) diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js new file mode 100644 index 000000000..76803bdc8 --- /dev/null +++ b/tests/css-configuration.test.js @@ -0,0 +1,137 @@ +import { run, html, css } from './util/run' + +test('it does something', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` + +
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + } + + return run( + css` + @tailwind utilities; + + :theme { + --colors: unset; + --colors-mint-50: #f3fdfb; + --colors-mint-900: #043820; + --colors-plum-50: #f8f6fe; + --colors-plum-900: #120c64; + --colors-primary: theme(colors.mint.50); + + --font-family-display: Graphik, sans-serif; + --font-family-display--font-feature-settings: "cv11", "ss01"; + + --font-size-10xl: 10rem; + --font-size-10xl--line-height: 10rem; + + --spacing-1\/4: 25%; + --spacing-1\/2: 50%; + --spacing-3\/4: 75%; + --spacing-\32 xl: 20rem; + + --shadow--default: 0 3px 5px -2px hsl(220 3% 15% / 4%), 0 7px 14px -5px hsl(220 + 3% 15% / 6%); + + --animation-flash: flash 1s; + } + `, + config + ).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .animate-flash { + animation: 1s flash; + } + .px-1\/2 { + padding-left: 50%; + padding-right: 50%; + } + .px-1\/4 { + padding-left: 25%; + padding-right: 25%; + } + .px-2xl { + padding-left: 20rem; + padding-right: 20rem; + } + .px-3\/4 { + padding-left: 75%; + padding-right: 75%; + } + .font-display { + font-feature-settings: "cv11", "ss01"; + font-family: Graphik, sans-serif; + } + .text-10xl { + font-size: 10rem; + line-height: 10rem; + } + .text-mint-50 { + --tw-text-opacity: 1; + color: rgb(243 253 251 / var(--tw-text-opacity)); + } + .text-mint-900 { + --tw-text-opacity: 1; + color: rgb(4 56 32 / var(--tw-text-opacity)); + } + .text-plum-50 { + --tw-text-opacity: 1; + color: rgb(248 246 254 / var(--tw-text-opacity)); + } + .text-plum-900 { + --tw-text-opacity: 1; + color: rgb(18 12 100 / var(--tw-text-opacity)); + } + .text-primary { + color: #f3fdfb; + } + .shadow { + --tw-shadow: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f; + --tw-shadow-colored: 0 3px 5px -2px var(--tw-shadow-color), 0 7px 14px -5px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + :root { + --colors-mint-50: #f3fdfb; + --colors-mint-900: #043820; + --colors-plum-50: #f8f6fe; + --colors-plum-900: #120c64; + --colors-primary: #f3fdfb; + --font-family-display: Graphik, sans-serif; + --font-family-display--font-feature-settings: "cv11", "ss01"; + --font-size-10xl: 10rem; + --font-size-10xl--line-height: 10rem; + --spacing-1\/4: 25%; + --spacing-1\/2: 50%; + --spacing-3\/4: 75%; + --spacing-2xl: 20rem; + --shadow--default: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f; + --animation-flash: flash 1s; + } + `) + }) +}) diff --git a/tests/custom-extractors.test.js b/tests/custom-extractors.test.js index 089084e77..f5933b7a5 100644 --- a/tests/custom-extractors.test.js +++ b/tests/custom-extractors.test.js @@ -1,4 +1,4 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' function customExtractor(content) { let matches = content.match(/class="([^"]+)"/) @@ -21,117 +21,109 @@ let expected = css` } ` -crosscheck(({ stable, oxide }) => { - describe('modern', () => { - oxide.test.todo('extract.DEFAULT') - stable.test('extract.DEFAULT', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: { - DEFAULT: customExtractor, - }, +describe('modern', () => { + test('extract.DEFAULT', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: { + DEFAULT: customExtractor, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('extract.{extension}') - stable.test('extract.{extension}', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: { - html: customExtractor, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('extract function') - stable.test('extract function', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: customExtractor, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('raw content with extension') - stable.test('raw content with extension', () => { - let config = { - content: { - files: [ - { - raw: sharedHtml, - extension: 'html', - }, - ], - extract: { - html: () => ['invisible'], - }, - }, - corePlugins: { preflight: false }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .invisible { - visibility: hidden; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) }) - describe('legacy', () => { - oxide.test.todo('defaultExtractor') - stable.test('defaultExtractor', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - options: { - defaultExtractor: customExtractor, - }, + test('extract.{extension}', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: { + html: customExtractor, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) + }) - oxide.test.todo('extractors array') - stable.test('extractors array', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - options: { - extractors: [ - { - extractor: customExtractor, - extensions: ['html'], - }, - ], + test('extract function', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: customExtractor, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) + }) + }) + + test('raw content with extension', () => { + let config = { + content: { + files: [ + { + raw: sharedHtml, + extension: 'html', }, + ], + extract: { + html: () => ['invisible'], }, - } + }, + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .invisible { + visibility: hidden; + } + `) + }) + }) +}) + +describe('legacy', () => { + test('defaultExtractor', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + options: { + defaultExtractor: customExtractor, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) + }) + }) + + test('extractors array', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + options: { + extractors: [ + { + extractor: customExtractor, + extensions: ['html'], + }, + ], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) }) }) diff --git a/tests/custom-plugins.test.js b/tests/custom-plugins.test.js index d91843199..ac3547317 100644 --- a/tests/custom-plugins.test.js +++ b/tests/custom-plugins.test.js @@ -1,18 +1,1132 @@ import createPlugin from '../src/public/create-plugin' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('plugins can create utilities with object syntax', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities }) { +test('plugins can create utilities with object syntax', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with arrays of objects', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities }) { + addUtilities([ + { + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', + }, + }, + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities, postcss }) { + addUtilities([ + postcss.rule({ selector: '.custom-object-fill' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'fill', + }), + ]), + postcss.rule({ selector: '.custom-object-contain' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'contain', + }), + ]), + postcss.rule({ selector: '.custom-object-cover' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'cover', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with mixed object styles and PostCSS nodes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities, postcss }) { + addUtilities([ + { + '.custom-object-fill': { + objectFit: 'fill', + }, + }, + postcss.rule({ selector: '.custom-object-contain' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'contain', + }), + ]), + postcss.rule({ selector: '.custom-object-cover' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'cover', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create components with object syntax', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + color: 'white', + padding: '.5rem 1rem', + borderRadius: '.25rem', + }, + '.btn-blue:hover': { + backgroundColor: 'darkblue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can add base styles with object syntax', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addBase }) { + addBase({ + img: { + maxWidth: '100%', + }, + button: { + fontFamily: 'inherit', + }, + }) + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + img { + max-width: 100%; + } + button { + font-family: inherit; + } + ${defaults} + `) + }) +}) + +test('plugins can add base styles with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addBase, postcss }) { + addBase([ + postcss.rule({ selector: 'img' }).append([ + postcss.decl({ + prop: 'max-width', + value: '100%', + }), + ]), + postcss.rule({ selector: 'button' }).append([ + postcss.decl({ + prop: 'font-family', + value: 'inherit', + }), + ]), + ]) + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + img { + max-width: 100%; + } + button { + font-family: inherit; + } + ${defaults} + `) + }) +}) + +test('plugins can create components with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents, postcss }) { + addComponents([ + postcss.rule({ selector: '.btn-blue' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'blue', + }), + postcss.decl({ + prop: 'color', + value: 'white', + }), + postcss.decl({ + prop: 'padding', + value: '.5rem 1rem', + }), + postcss.decl({ + prop: 'border-radius', + value: '.25rem', + }), + ]), + postcss.rule({ selector: '.btn-blue:hover' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'darkblue', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can create components with mixed object styles and raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents, postcss }) { + addComponents([ + postcss.rule({ selector: '.btn-blue' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'blue', + }), + postcss.decl({ + prop: 'color', + value: 'white', + }), + postcss.decl({ + prop: 'padding', + value: '.5rem 1rem', + }), + postcss.decl({ + prop: 'border-radius', + value: '.25rem', + }), + ]), + { + '.btn-blue:hover': { + backgroundColor: 'darkblue', + }, + }, + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can create components with media queries with object syntax', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.custom-container': { + width: '100%', + }, + '@media (min-width: 100px)': { + '.custom-container': { + maxWidth: '100px', + }, + }, + '@media (min-width: 200px)': { + '.custom-container': { + maxWidth: '200px', + }, + }, + '@media (min-width: 300px)': { + '.custom-container': { + maxWidth: '300px', + }, + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 100px) { + .custom-container { + max-width: 100px; + } + } + @media (min-width: 200px) { + .custom-container { + max-width: 200px; + } + } + @media (min-width: 300px) { + .custom-container { + max-width: 300px; + } + } + `) + }) +}) + +test('media queries can be defined multiple times using objects-in-array syntax', () => { + let config = { + content: [ + { + raw: html`
+ `, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents([ + { + '.custom-container': { + width: '100%', + }, + '@media (min-width: 100px)': { + '.custom-container': { + maxWidth: '100px', + }, + }, + }, + { + '.btn': { + padding: '1rem .5rem', + display: 'block', + }, + '@media (min-width: 100px)': { + '.btn': { + display: 'inline-block', + }, + }, + }, + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 100px) { + .custom-container { + max-width: 100px; + } + } + .btn { + padding: 1rem 0.5rem; + display: block; + } + @media (min-width: 100px) { + .btn { + display: inline-block; + } + } + `) + }) +}) + +test('plugins can create nested rules', () => { + let config = { + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + color: 'white', + padding: '.5rem 1rem', + borderRadius: '.25rem', + '&:hover': { + backgroundColor: 'darkblue', + }, + '@media (min-width: 500px)': { + '&:hover': { + backgroundColor: 'orange', + }, + }, + '> a': { + color: 'red', + }, + 'h1 &': { + color: 'purple', + }, + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + @media (min-width: 500px) { + .btn-blue:hover { + background-color: orange; + } + } + .btn-blue > a { + color: red; + } + h1 .btn-blue { + color: purple; + } + `) + }) +}) + +test('plugins can create rules with escaped selectors', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ e, addUtilities }) { + addUtilities({ + [`.${e('custom-top-1/4')}`]: { + top: '25%', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-top-1\/4 { + top: 25%; + } + `) + }) +}) + +test('plugins can access the current config', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addComponents, config }) { + let containerClasses = [ + { + '.custom-container': { + width: '100%', + }, + }, + ] + + for (let maxWidth of Object.values(config('theme.customScreens'))) { + containerClasses.push({ + [`@media (min-width: ${maxWidth})`]: { + '.custom-container': { maxWidth }, + }, + }) + } + + addComponents(containerClasses) + }, + ], + theme: { + customScreens: { + sm: '576px', + md: '768px', + lg: '992px', + xl: '1200px', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 576px) { + .custom-container { + max-width: 576px; + } + } + @media (min-width: 768px) { + .custom-container { + max-width: 768px; + } + } + @media (min-width: 992px) { + .custom-container { + max-width: 992px; + } + } + @media (min-width: 1200px) { + .custom-container { + max-width: 1200px; + } + } + `) + }) +}) + +test('plugins can check if corePlugins are enabled', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities, corePlugins }) { + addUtilities({ + '.test': { + 'text-color': corePlugins('textColor') ? 'true' : 'false', + opacity: corePlugins('opacity') ? 'true' : 'false', + }, + }) + }, + ], + corePlugins: { textColor: false }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test { + text-color: false; + opacity: true; + } + `) + }) +}) + +test('plugins can check if corePlugins are enabled when using array white-listing', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities, corePlugins }) { + addUtilities({ + '.test': { + 'text-color': corePlugins('textColor') ? 'true' : 'false', + opacity: corePlugins('opacity') ? 'true' : 'false', + }, + }) + }, + ], + corePlugins: ['textColor'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test { + text-color: true; + opacity: false; + } + `) + }) +}) + +test('plugins can provide fallbacks to keys missing from the config', () => { + let config = { + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents, config }) { + addComponents({ + '.btn': { + borderRadius: config('borderRadius.default', '.25rem'), + }, + }) + }, + ], + theme: { + borderRadius: { + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn { + border-radius: 0.25rem; + } + `) + }) +}) + +test('plugins can add multiple sets of utilities and components', () => { + let config = { + content: [ + { + raw: html` +
`, + }, + ], + plugins: [ + function ({ addUtilities, addComponents }) { + addComponents({ + '.card': { + padding: '1rem', + borderRadius: '.25rem', + }, + }) + + addUtilities({ + '.custom-skew-12deg': { + transform: 'skewY(-12deg)', + }, + }) + + addComponents({ + '.btn': { + padding: '1rem .5rem', + display: 'inline-block', + }, + }) + + addUtilities({ + '.custom-border-collapse': { + borderCollapse: 'collapse', + }, + }) + }, + ], + } + + return run('@tailwind components; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .card { + border-radius: 0.25rem; + padding: 1rem; + } + .btn { + padding: 1rem 0.5rem; + display: inline-block; + } + .custom-skew-12deg { + transform: skewY(-12deg); + } + .custom-border-collapse { + border-collapse: collapse; + } + `) + }) +}) + +test('plugins respect prefix and important options by default when adding utilities', () => { + let config = { + prefix: 'tw-', + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-custom-rotate-90 { + transform: rotate(90deg) !important; + } + `) + }) +}) + +test('when important is a selector it is used to scope utilities instead of adding !important', () => { + let config = { + prefix: 'tw-', + important: '#app', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + #app .tw-custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('when important is a selector it scopes all selectors in a rule, even though defining utilities like this is stupid', () => { + let config = { + important: '#app', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90, .custom-rotate-1\\/4': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + #app .custom-rotate-90, + #app .custom-rotate-1\/4 { + transform: rotate(90deg); + } + `) + }) +}) + +test('important utilities are not made double important when important option is used', () => { + let config = { + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg) !important', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg) !important; + } + `) + }) +}) + +test("component declarations respect the 'prefix' option by default", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue { + background-color: #00f; + } + `) + }) +}) + +test('all selectors in a rule are prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
`, + }, + ], + plugins: [ + function ({ addUtilities, addComponents }) { + addUtilities({ + '.custom-rotate-90, .custom-rotate-1\\/4': { + transform: 'rotate(90deg)', + }, + }) + addComponents({ + '.btn-blue, .btn-red': { + padding: '10px', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue, + .tw-btn-red { + padding: 10px; + } + `) + }) +}) + +test("component declarations can optionally ignore 'prefix' option", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents( + { + '.btn-blue': { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + background-color: #00f; + } + `) + }) +}) + +test("component declarations are not affected by the 'important' option", () => { + let config = { + important: true, + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + background-color: #00f; + } + `) + }) +}) + +test("plugins can apply the user's chosen prefix to components manually", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents, prefix }) { + addComponents( + { + [prefix('.btn-blue')]: { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue { + background-color: #00f; + } + `) + }) +}) + +test('prefix can optionally be ignored for utilities', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities( + { + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('important can optionally be ignored for utilities', () => { + let config = { + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities( + { + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('prefix will prefix all classes in a selector', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + plugins: [ + function ({ addComponents, prefix }) { + addComponents( + { + [prefix('.btn-blue .w-1\\/4 > h1.text-xl + a .bar')]: { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue .tw-w-1\/4 > h1.tw-text-xl + a .tw-bar { + background-color: #00f; + } + `) + }) +}) + +test('plugins can be provided as an object with a handler function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + { + handler({ addUtilities }) { addUtilities({ '.custom-object-fill': { 'object-fit': 'fill', @@ -25,1273 +1139,95 @@ crosscheck(() => { }, }) }, - ], - } + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) }) +}) - test('plugins can create utilities with arrays of objects', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities }) { - addUtilities([ - { - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }, - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create utilities with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities, postcss }) { - addUtilities([ - postcss.rule({ selector: '.custom-object-fill' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'fill', - }), - ]), - postcss.rule({ selector: '.custom-object-contain' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'contain', - }), - ]), - postcss.rule({ selector: '.custom-object-cover' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'cover', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create utilities with mixed object styles and PostCSS nodes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities, postcss }) { - addUtilities([ - { - '.custom-object-fill': { - objectFit: 'fill', - }, - }, - postcss.rule({ selector: '.custom-object-contain' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'contain', - }), - ]), - postcss.rule({ selector: '.custom-object-cover' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'cover', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create components with object syntax', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - color: 'white', - padding: '.5rem 1rem', - borderRadius: '.25rem', - }, - '.btn-blue:hover': { - backgroundColor: 'darkblue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can add base styles with object syntax', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addBase }) { - addBase({ - img: { - maxWidth: '100%', - }, - button: { - fontFamily: 'inherit', - }, - }) - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - img { - max-width: 100%; - } - button { - font-family: inherit; - } - ${defaults} - `) - }) - }) - - test('plugins can add base styles with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addBase, postcss }) { - addBase([ - postcss.rule({ selector: 'img' }).append([ - postcss.decl({ - prop: 'max-width', - value: '100%', - }), - ]), - postcss.rule({ selector: 'button' }).append([ - postcss.decl({ - prop: 'font-family', - value: 'inherit', - }), - ]), - ]) - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - img { - max-width: 100%; - } - button { - font-family: inherit; - } - ${defaults} - `) - }) - }) - - test('plugins can create components with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents, postcss }) { - addComponents([ - postcss.rule({ selector: '.btn-blue' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'blue', - }), - postcss.decl({ - prop: 'color', - value: 'white', - }), - postcss.decl({ - prop: 'padding', - value: '.5rem 1rem', - }), - postcss.decl({ - prop: 'border-radius', - value: '.25rem', - }), - ]), - postcss.rule({ selector: '.btn-blue:hover' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'darkblue', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can create components with mixed object styles and raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents, postcss }) { - addComponents([ - postcss.rule({ selector: '.btn-blue' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'blue', - }), - postcss.decl({ - prop: 'color', - value: 'white', - }), - postcss.decl({ - prop: 'padding', - value: '.5rem 1rem', - }), - postcss.decl({ - prop: 'border-radius', - value: '.25rem', - }), - ]), - { - '.btn-blue:hover': { - backgroundColor: 'darkblue', - }, - }, - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can create components with media queries with object syntax', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.custom-container': { - width: '100%', - }, - '@media (min-width: 100px)': { - '.custom-container': { - maxWidth: '100px', - }, - }, - '@media (min-width: 200px)': { - '.custom-container': { - maxWidth: '200px', - }, - }, - '@media (min-width: 300px)': { - '.custom-container': { - maxWidth: '300px', - }, - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 100px) { - .custom-container { - max-width: 100px; - } - } - @media (min-width: 200px) { - .custom-container { - max-width: 200px; - } - } - @media (min-width: 300px) { - .custom-container { - max-width: 300px; - } - } - `) - }) - }) - - test('media queries can be defined multiple times using objects-in-array syntax', () => { - let config = { - content: [ - { - raw: html`
- `, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents([ - { - '.custom-container': { - width: '100%', - }, - '@media (min-width: 100px)': { - '.custom-container': { - maxWidth: '100px', - }, - }, - }, - { - '.btn': { - padding: '1rem .5rem', - display: 'block', - }, - '@media (min-width: 100px)': { - '.btn': { - display: 'inline-block', - }, - }, - }, - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 100px) { - .custom-container { - max-width: 100px; - } - } - .btn { - padding: 1rem 0.5rem; - display: block; - } - @media (min-width: 100px) { - .btn { - display: inline-block; - } - } - `) - }) - }) - - test('plugins can create nested rules', () => { - let config = { - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - color: 'white', - padding: '.5rem 1rem', - borderRadius: '.25rem', - '&:hover': { - backgroundColor: 'darkblue', - }, - '@media (min-width: 500px)': { - '&:hover': { - backgroundColor: 'orange', - }, - }, - '> a': { - color: 'red', - }, - 'h1 &': { - color: 'purple', - }, - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - @media (min-width: 500px) { - .btn-blue:hover { - background-color: orange; - } - } - .btn-blue > a { - color: red; - } - h1 .btn-blue { - color: purple; - } - `) - }) - }) - - test('plugins can create rules with escaped selectors', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ e, addUtilities }) { - addUtilities({ - [`.${e('custom-top-1/4')}`]: { - top: '25%', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-top-1\/4 { - top: 25%; - } - `) - }) - }) - - test('plugins can access the current config', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addComponents, config }) { - let containerClasses = [ - { - '.custom-container': { - width: '100%', - }, - }, - ] - - for (let maxWidth of Object.values(config('theme.customScreens'))) { - containerClasses.push({ - [`@media (min-width: ${maxWidth})`]: { - '.custom-container': { maxWidth }, - }, - }) - } - - addComponents(containerClasses) - }, - ], - theme: { - customScreens: { - sm: '576px', - md: '768px', - lg: '992px', - xl: '1200px', +test('plugins can provide a config but no handler', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 576px) { - .custom-container { - max-width: 576px; - } - } - @media (min-width: 768px) { - .custom-container { - max-width: 768px; - } - } - @media (min-width: 992px) { - .custom-container { - max-width: 992px; - } - } - @media (min-width: 1200px) { - .custom-container { - max-width: 1200px; - } - } - `) - }) - }) - - test('plugins can check if corePlugins are enabled', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities, corePlugins }) { + { + handler({ addUtilities }) { addUtilities({ - '.test': { - 'text-color': corePlugins('textColor') ? 'true' : 'false', - opacity: corePlugins('opacity') ? 'true' : 'false', + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', }, }) }, - ], - corePlugins: { textColor: false }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test { - text-color: false; - opacity: true; - } - `) - }) - }) - - test('plugins can check if corePlugins are enabled when using array white-listing', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities, corePlugins }) { - addUtilities({ - '.test': { - 'text-color': corePlugins('textColor') ? 'true' : 'false', - opacity: corePlugins('opacity') ? 'true' : 'false', - }, - }) - }, - ], - corePlugins: ['textColor'], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test { - text-color: true; - opacity: false; - } - `) - }) - }) - - test('plugins can provide fallbacks to keys missing from the config', () => { - let config = { - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents, config }) { - addComponents({ - '.btn': { - borderRadius: config('borderRadius.default', '.25rem'), - }, - }) - }, - ], - theme: { - borderRadius: { - 1: '1px', - 2: '2px', - 4: '4px', - 8: '8px', - }, }, - } + ], + } - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn { - border-radius: 0.25rem; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-custom-object-fill { + object-fit: fill; + } + .tw-custom-object-contain { + object-fit: contain; + } + .tw-custom-object-cover { + object-fit: cover; + } + `) }) +}) - test('plugins can add multiple sets of utilities and components', () => { - let config = { - content: [ - { - raw: html` -
`, - }, - ], - plugins: [ - function ({ addUtilities, addComponents }) { - addComponents({ - '.card': { - padding: '1rem', - borderRadius: '.25rem', - }, - }) - - addUtilities({ - '.custom-skew-12deg': { - transform: 'skewY(-12deg)', - }, - }) - - addComponents({ - '.btn': { - padding: '1rem .5rem', - display: 'inline-block', - }, - }) - - addUtilities({ - '.custom-border-collapse': { - borderCollapse: 'collapse', - }, - }) - }, - ], - } - - return run('@tailwind components; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .card { - border-radius: 0.25rem; - padding: 1rem; - } - .btn { - padding: 1rem 0.5rem; - display: inline-block; - } - .custom-skew-12deg { - transform: skewY(-12deg); - } - .custom-border-collapse { - border-collapse: collapse; - } - `) - }) - }) - - test('plugins respect prefix and important options by default when adding utilities', () => { - let config = { - prefix: 'tw-', - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-custom-rotate-90 { - transform: rotate(90deg) !important; - } - `) - }) - }) - - test('when important is a selector it is used to scope utilities instead of adding !important', () => { - let config = { - prefix: 'tw-', - important: '#app', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - #app .tw-custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('when important is a selector it scopes all selectors in a rule, even though defining utilities like this is stupid', () => { - let config = { - important: '#app', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90, .custom-rotate-1\\/4': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - #app .custom-rotate-90, - #app .custom-rotate-1\/4 { - transform: rotate(90deg); - } - `) - }) - }) - - test('important utilities are not made double important when important option is used', () => { - let config = { - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg) !important', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg) !important; - } - `) - }) - }) - - test("component declarations respect the 'prefix' option by default", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue { - background-color: #00f; - } - `) - }) - }) - - test('all selectors in a rule are prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
`, - }, - ], - plugins: [ - function ({ addUtilities, addComponents }) { - addUtilities({ - '.custom-rotate-90, .custom-rotate-1\\/4': { - transform: 'rotate(90deg)', - }, - }) - addComponents({ - '.btn-blue, .btn-red': { - padding: '10px', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue, - .tw-btn-red { - padding: 10px; - } - `) - }) - }) - - test("component declarations can optionally ignore 'prefix' option", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents( - { - '.btn-blue': { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - background-color: #00f; - } - `) - }) - }) - - test("component declarations are not affected by the 'important' option", () => { - let config = { - important: true, - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - background-color: #00f; - } - `) - }) - }) - - test("plugins can apply the user's chosen prefix to components manually", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents, prefix }) { - addComponents( - { - [prefix('.btn-blue')]: { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue { - background-color: #00f; - } - `) - }) - }) - - test('prefix can optionally be ignored for utilities', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities( - { - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('important can optionally be ignored for utilities', () => { - let config = { - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities( - { - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }, - { respectImportant: false } - ) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('prefix will prefix all classes in a selector', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - plugins: [ - function ({ addComponents, prefix }) { - addComponents( - { - [prefix('.btn-blue .w-1\\/4 > h1.text-xl + a .bar')]: { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue .tw-w-1\/4 > h1.tw-text-xl + a .tw-bar { - background-color: #00f; - } - `) - }) - }) - - test('plugins can be provided as an object with a handler function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - { - handler({ addUtilities }) { - addUtilities({ - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }) - }, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can provide a config but no handler', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - { - handler({ addUtilities }) { - addUtilities({ - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }) - }, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-custom-object-fill { - object-fit: fill; - } - .tw-custom-object-contain { - object-fit: contain; - } - .tw-custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can be created using the `createPlugin` function', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, +test('plugins can be created using the `createPlugin` function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + screens: { + sm: '400px', }, - plugins: [ - createPlugin( - function ({ addUtilities, theme }) { - addUtilities( - Object.fromEntries( - Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.test-${k}`, - { testProperty: v }, - ]) - ) - ) - }, - { - theme: { - testPlugin: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - }, - } - ), - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test-sm { - test-property: 1rem; - } - .test-md { - test-property: 2rem; - } - .test-lg { - test-property: 3rem; - } - .hover\:test-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:test-sm { - test-property: 1rem; - } - } - `) - }) - }) - - test('plugins with extra options can be created using the `createPlugin.withOptions` function', () => { - let plugin = createPlugin.withOptions( - function ({ className }) { - return function ({ addUtilities, theme }) { + }, + plugins: [ + createPlugin( + function ({ addUtilities, theme }) { addUtilities( Object.fromEntries( Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.${className}-${k}`, + `.test-${k}`, { testProperty: v }, ]) ) ) - } - }, - function () { - return { + }, + { theme: { testPlugin: { sm: '1rem', @@ -1300,169 +1236,36 @@ crosscheck(() => { }, }, } + ), + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-sm { + test-property: 1rem; } - ) - - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - plugins: [plugin({ className: 'banana' })], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1rem; - } - .banana-md { - test-property: 2rem; - } - .banana-lg { - test-property: 3rem; - } - .hover\:banana-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1rem; - } - } - `) - }) - }) - - test('plugins should cache correctly', () => { - let plugin = createPlugin.withOptions( - ({ className = 'banana' } = {}) => - ({ addComponents }) => { - addComponents({ [`.${className}`]: { position: 'absolute' } }) - } - ) - - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - } - - function internalRun(options = {}) { - return run('@tailwind components', { - ...config, - plugins: [plugin(options)], - }) - } - - return Promise.all([internalRun(), internalRun({ className: 'apple' })]).then( - ([result1, result2]) => { - let expected1 = css` - .banana { - position: absolute; - } - @media (min-width: 400px) { - .sm\:banana { - position: absolute; - } - } - ` - - let expected2 = css` - .apple { - position: absolute; - } - @media (min-width: 400px) { - .sm\:apple { - position: absolute; - } - } - ` - - expect(result1.css).toMatchCss(expected1) - expect(result2.css).toMatchCss(expected2) + .test-md { + test-property: 2rem; } - ) - }) - - test('plugins created using `createPlugin.withOptions` do not need to be invoked if the user wants to use the default options', () => { - let plugin = createPlugin.withOptions( - function ({ className } = { className: 'banana' }) { - return function ({ addUtilities, theme }) { - addUtilities( - Object.fromEntries( - Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.${className}-${k}`, - { testProperty: v }, - ]) - ) - ) - } - }, - function () { - return { - theme: { - testPlugin: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - }, + .test-lg { + test-property: 3rem; + } + .hover\:test-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:test-sm { + test-property: 1rem; } } - ) - - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - plugins: [plugin], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1rem; - } - .banana-md { - test-property: 2rem; - } - .banana-lg { - test-property: 3rem; - } - .hover\:banana-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1rem; - } - } - `) - }) + `) }) +}) - test('the configFunction parameter is optional when using the `createPlugin.withOptions` function', () => { - let plugin = createPlugin.withOptions(function ({ className }) { +test('plugins with extra options can be created using the `createPlugin.withOptions` function', () => { + let plugin = createPlugin.withOptions( + function ({ className }) { return function ({ addUtilities, theme }) { addUtilities( Object.fromEntries( @@ -1473,461 +1276,641 @@ crosscheck(() => { ) ) } - }) - - let config = { - content: [ - { - raw: html`
`, + }, + function () { + return { + theme: { + testPlugin: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - testPlugin: { - sm: '1px', - md: '2px', - lg: '3px', - }, - }, - plugins: [plugin({ className: 'banana' })], + } } + ) - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1px; + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + plugins: [plugin({ className: 'banana' })], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1rem; + } + .banana-md { + test-property: 2rem; + } + .banana-lg { + test-property: 3rem; + } + .hover\:banana-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1rem; } - .banana-md { - test-property: 2px; - } - .banana-lg { - test-property: 3px; - } - .hover\:banana-sm:hover { - test-property: 1px; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1px; - } - } - `) - }) + } + `) + }) +}) + +test('plugins should cache correctly', () => { + let plugin = createPlugin.withOptions(({ className = 'banana' } = {}) => ({ addComponents }) => { + addComponents({ [`.${className}`]: { position: 'absolute' } }) }) - test('keyframes are not escaped', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [ - function ({ matchUtilities }) { - matchUtilities({ - foo: (value) => { - return { - [`@keyframes ${value}`]: { - '25.001%': { - color: 'black', - }, - }, - animation: `${value} 1s infinite`, - } - }, - }) - }, - ], - } + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes abc { + function internalRun(options = {}) { + return run('@tailwind components', { + ...config, + plugins: [plugin(options)], + }) + } + + return Promise.all([internalRun(), internalRun({ className: 'apple' })]).then( + ([result1, result2]) => { + let expected1 = css` + .banana { + position: absolute; + } + @media (min-width: 400px) { + .sm\:banana { + position: absolute; + } + } + ` + + let expected2 = css` + .apple { + position: absolute; + } + @media (min-width: 400px) { + .sm\:apple { + position: absolute; + } + } + ` + + expect(result1.css).toMatchFormattedCss(expected1) + expect(result2.css).toMatchFormattedCss(expected2) + } + ) +}) + +test('plugins created using `createPlugin.withOptions` do not need to be invoked if the user wants to use the default options', () => { + let plugin = createPlugin.withOptions( + function ({ className } = { className: 'banana' }) { + return function ({ addUtilities, theme }) { + addUtilities( + Object.fromEntries( + Object.entries(theme('testPlugin')).map(([k, v]) => [ + `.${className}-${k}`, + { testProperty: v }, + ]) + ) + ) + } + }, + function () { + return { + theme: { + testPlugin: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, + }, + } + } + ) + + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + plugins: [plugin], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1rem; + } + .banana-md { + test-property: 2rem; + } + .banana-lg { + test-property: 3rem; + } + .hover\:banana-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1rem; + } + } + `) + }) +}) + +test('the configFunction parameter is optional when using the `createPlugin.withOptions` function', () => { + let plugin = createPlugin.withOptions(function ({ className }) { + return function ({ addUtilities, theme }) { + addUtilities( + Object.fromEntries( + Object.entries(theme('testPlugin')).map(([k, v]) => [ + `.${className}-${k}`, + { testProperty: v }, + ]) + ) + ) + } + }) + + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + testPlugin: { + sm: '1px', + md: '2px', + lg: '3px', + }, + }, + plugins: [plugin({ className: 'banana' })], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1px; + } + .banana-md { + test-property: 2px; + } + .banana-lg { + test-property: 3px; + } + .hover\:banana-sm:hover { + test-property: 1px; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1px; + } + } + `) + }) +}) + +test('keyframes are not escaped', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ matchUtilities }) { + matchUtilities({ + foo: (value) => { + return { + [`@keyframes ${value}`]: { + '25.001%': { + color: 'black', + }, + }, + animation: `${value} 1s infinite`, + } + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes abc { + 25.001% { + color: #000; + } + } + .foo-\[abc\] { + animation: 1s infinite abc; + } + @media (min-width: 768px) { + @keyframes def { 25.001% { color: #000; } } - .foo-\[abc\] { - animation: 1s infinite abc; + .md\:foo-\[def\] { + animation: 1s infinite def; } - @media (min-width: 768px) { - @keyframes def { - 25.001% { - color: #000; - } - } - .md\:foo-\[def\] { - animation: 1s infinite def; - } - } - `) - }) - }) - - test('font sizes are retrieved without default line-heights or letter-spacing using theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - fontSize: { - sm: ['14px', '20px'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - fontSize: theme('fontSize.sm'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - font-size: 14px; - } - `) - }) - }) - - test('outlines are retrieved without outline-offset using theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - outline: { - black: ['2px dotted black', '4px'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - outline: theme('outline.black'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - outline: 2px dotted #000; - } - `) - }) - }) - - test('box-shadow values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - boxShadow: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - boxShadow: theme('boxShadow.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - box-shadow: width, height; - } - `) - }) - }) - - test('transition-property values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionProperty: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionProperty: theme('transitionProperty.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-property: width, height; - } - `) - }) - }) - - test('transition-duration values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionDuration: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionDuration: theme('transitionDuration.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-duration: width, height; - } - `) - }) - }) - - test('transition-delay values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionDuration: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionDuration: theme('transitionDuration.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-duration: width, height; - } - `) - }) - }) - - test('transition-timing-function values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionTimingFunction: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionTimingFunction: theme('transitionTimingFunction.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-timing-function: width, height; - } - `) - }) - }) - - test('background-image values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundImage: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundImage: theme('backgroundImage.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-image: width, height; - } - `) - }) - }) - - test('background-size values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundSize: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundSize: theme('backgroundSize.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-size: width, height; - } - `) - }) - }) - - test('background-color values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundColor: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundColor: theme('backgroundColor.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-color: width, height; - } - `) - }) - }) - - test('cursor values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - cursor: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - cursor: theme('cursor.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - cursor: width, height; - } - `) - }) - }) - - test('animation values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - animation: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - animation: theme('animation.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - animation: width, height; - } - `) - }) - }) - - test('custom properties are not converted to kebab-case when added to base layer', () => { - let config = { - content: [], - plugins: [ - function ({ addBase }) { - addBase({ - ':root': { - '--colors-primaryThing-500': '0, 0, 255', - }, - }) - }, - ], - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`) - }) + } + `) + }) +}) + +test('font sizes are retrieved without default line-heights or letter-spacing using theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + fontSize: { + sm: ['14px', '20px'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + fontSize: theme('fontSize.sm'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + font-size: 14px; + } + `) + }) +}) + +test('outlines are retrieved without outline-offset using theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + outline: { + black: ['2px dotted black', '4px'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + outline: theme('outline.black'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + outline: 2px dotted #000; + } + `) + }) +}) + +test('box-shadow values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + boxShadow: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + boxShadow: theme('boxShadow.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + box-shadow: width, height; + } + `) + }) +}) + +test('transition-property values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionProperty: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionProperty: theme('transitionProperty.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-property: width, height; + } + `) + }) +}) + +test('transition-duration values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionDuration: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionDuration: theme('transitionDuration.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-duration: width, height; + } + `) + }) +}) + +test('transition-delay values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionDuration: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionDuration: theme('transitionDuration.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-duration: width, height; + } + `) + }) +}) + +test('transition-timing-function values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionTimingFunction: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionTimingFunction: theme('transitionTimingFunction.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-timing-function: width, height; + } + `) + }) +}) + +test('background-image values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundImage: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundImage: theme('backgroundImage.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-image: width, height; + } + `) + }) +}) + +test('background-size values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundSize: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundSize: theme('backgroundSize.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-size: width, height; + } + `) + }) +}) + +test('background-color values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundColor: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundColor: theme('backgroundColor.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-color: width, height; + } + `) + }) +}) + +test('cursor values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + cursor: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + cursor: theme('cursor.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + cursor: width, height; + } + `) + }) +}) + +test('animation values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + animation: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + animation: theme('animation.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + animation: width, height; + } + `) + }) +}) + +test('custom properties are not converted to kebab-case when added to base layer', () => { + let config = { + content: [], + plugins: [ + function ({ addBase }) { + addBase({ + ':root': { + '--colors-primaryThing-500': '0, 0, 255', + }, + }) + }, + ], + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`) }) }) diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index adc1d55af..3b1708dfb 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -1,57 +1,55 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('custom separator', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - separator: '_', - } +test('custom separator', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, + }, + ], + separator: '_', + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group:hover .group-hover_focus-within_text-left:focus-within { - text-align: left; - } - :is([dir='rtl'] .rtl_active_text-center:active) { + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group:hover .group-hover_focus-within_text-left:focus-within { + text-align: left; + } + :is([dir='rtl'] .rtl_active_text-center:active) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe_hover_text-center:hover { text-align: center; } - @media (prefers-reduced-motion: no-preference) { - .motion-safe_hover_text-center:hover { - text-align: center; - } + } + :is(.dark .dark_focus_text-left:focus) { + text-align: left; + } + @media (min-width: 768px) { + .md_hover_text-right:hover { + text-align: right; } - :is(.dark .dark_focus_text-left:focus) { - text-align: left; - } - @media (min-width: 768px) { - .md_hover_text-right:hover { - text-align: right; - } - } - `) - }) - }) - - test('dash is not supported', () => { - let config = { - darkMode: 'class', - content: [{ raw: 'lg-hover-font-bold' }], - separator: '-', - } - - return expect(run('@tailwind utilities', config)).rejects.toThrowError( - "The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead." - ) + } + `) }) }) + +test('dash is not supported', () => { + let config = { + darkMode: 'class', + content: [{ raw: 'lg-hover-font-bold' }], + separator: '-', + } + + return expect(run('@tailwind utilities', config)).rejects.toThrowError( + "The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead." + ) +}) diff --git a/tests/custom-transformers.test.js b/tests/custom-transformers.test.js index 14e3abac0..2715a7155 100644 --- a/tests/custom-transformers.test.js +++ b/tests/custom-transformers.test.js @@ -1,72 +1,67 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' function customTransformer(content) { return content.replace(/uppercase/g, 'lowercase') } -crosscheck(({ stable, oxide }) => { - oxide.test.todo('transform function') - stable.test('transform function', () => { - let config = { - content: { - files: [{ raw: html`
` }], - transform: customTransformer, - }, - } +test('transform function', () => { + let config = { + content: { + files: [{ raw: html`
` }], + transform: customTransformer, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .lowercase { - text-transform: lowercase; - } - `) - }) - }) - - oxide.test.todo('transform.DEFAULT') - stable.test('transform.DEFAULT', () => { - let config = { - content: { - files: [{ raw: html`
` }], - transform: { - DEFAULT: customTransformer, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .lowercase { - text-transform: lowercase; - } - `) - }) - }) - - oxide.test.todo('transform.{extension}') - stable.test('transform.{extension}', () => { - let config = { - content: { - files: [ - { raw: 'blah blah blah', extension: 'html' }, - { raw: 'blah blah blah', extension: 'php' }, - ], - transform: { - html: () => 'uppercase', - php: () => 'lowercase', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - .lowercase { - text-transform: lowercase; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .lowercase { + text-transform: lowercase; + } + `) + }) +}) + +test('transform.DEFAULT', () => { + let config = { + content: { + files: [{ raw: html`
` }], + transform: { + DEFAULT: customTransformer, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .lowercase { + text-transform: lowercase; + } + `) + }) +}) + +test('transform.{extension}', () => { + let config = { + content: { + files: [ + { raw: 'blah blah blah', extension: 'html' }, + { raw: 'blah blah blah', extension: 'php' }, + ], + transform: { + html: () => 'uppercase', + php: () => 'lowercase', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + .lowercase { + text-transform: lowercase; + } + `) }) }) diff --git a/tests/customConfig.test.js b/tests/customConfig.test.js index 5b83f9f2e..b8f459144 100644 --- a/tests/customConfig.test.js +++ b/tests/customConfig.test.js @@ -2,37 +2,100 @@ import fs from 'fs' import path from 'path' import inTempDirectory from '../jest/runInTempDirectory' -import { crosscheck, run, html, css, javascript } from './util/run' +import { run, html, css, javascript } from './util/run' const defaultConfigFile = 'tailwind.config.js' const cjsConfigFile = 'tailwind.config.cjs' -crosscheck(() => { - test('it uses the values from the custom config file', () => { - let config = require(path.resolve(`${__dirname}/fixtures/custom-config.js`)) +test('it uses the values from the custom config file', () => { + let config = require(path.resolve(`${__dirname}/fixtures/custom-config.js`)) - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; } - `) - }) + } + `) }) +}) - test('custom config can be passed as an object', () => { - let config = { +test('custom config can be passed as an object', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + mobile: '400px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('custom config path can be passed using `config` property in an object', () => { + let config = { + config: path.resolve(`${__dirname}/fixtures/custom-config.js`), + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('custom config can be passed under the `config` property', () => { + let config = { + config: { content: [{ raw: html`
` }], theme: { screens: { mobile: '400px', }, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('tailwind.config.cjs is picked up by default', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(cjsConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` @media (min-width: 400px) { .mobile\:font-bold { @@ -42,349 +105,284 @@ crosscheck(() => { `) }) }) - - test('custom config path can be passed using `config` property in an object', () => { - let config = { - config: path.resolve(`${__dirname}/fixtures/custom-config.js`), - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('custom config can be passed under the `config` property', () => { - let config = { - config: { - content: [{ raw: html`
` }], - theme: { - screens: { - mobile: '400px', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('tailwind.config.cjs is picked up by default', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(cjsConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities').then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.js is picked up by default', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(defaultConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities').then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.cjs is picked up by default when passing an empty object', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(cjsConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities', {}).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.js is picked up by default when passing an empty object', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(defaultConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities', {}).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('the default config can be overridden using the presets key', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }, - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-0 { - min-height: 0; - } - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('presets can be functions', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - () => ({ - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }), - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-0 { - min-height: 0; - } - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('the default config can be removed by using an empty presets key in a preset', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - presets: [], - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }, - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('presets can have their own presets', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - presets: [], - theme: { - colors: { red: '#dd0000' }, - }, - }, - { - presets: [ - { - presets: [], - theme: { - colors: { - transparent: 'transparent', - red: '#ff0000', - }, - }, - }, - ], - theme: { - extend: { - colors: { - black: 'black', - red: '#ee0000', - }, - backgroundColor: (theme) => theme('colors'), - }, - }, - corePlugins: ['backgroundColor'], - }, - ], - theme: { - extend: { colors: { white: 'white' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-black { - background-color: #000; - } - .bg-red { - background-color: #e00; - } - .bg-transparent { - background-color: #0000; - } - .bg-white { - background-color: #fff; - } - `) - }) - }) - - test('function presets can be mixed with object presets', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - () => ({ - presets: [], - theme: { - colors: { red: '#dd0000' }, - }, - }), - { - presets: [ - () => ({ - presets: [], - theme: { - colors: { - transparent: 'transparent', - red: '#ff0000', - }, - }, - }), - ], - theme: { - extend: { - colors: { - black: 'black', - red: '#ee0000', - }, - backgroundColor: (theme) => theme('colors'), - }, - }, - corePlugins: ['backgroundColor'], - }, - ], - theme: { - extend: { colors: { white: 'white' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-black { - background-color: #000; - } - .bg-red { - background-color: #e00; - } - .bg-transparent { - background-color: #0000; - } - .bg-white { - background-color: #fff; - } - `) - }) - }) +}) + +test('tailwind.config.js is picked up by default', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(defaultConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities').then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('tailwind.config.cjs is picked up by default when passing an empty object', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(cjsConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities', {}).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('tailwind.config.js is picked up by default when passing an empty object', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(defaultConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities', {}).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('the default config can be overridden using the presets key', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }, + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-0 { + min-height: 0; + } + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('presets can be functions', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + () => ({ + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }), + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-0 { + min-height: 0; + } + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('the default config can be removed by using an empty presets key in a preset', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + presets: [], + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }, + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('presets can have their own presets', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + presets: [], + theme: { + colors: { red: '#dd0000' }, + }, + }, + { + presets: [ + { + presets: [], + theme: { + colors: { + transparent: 'transparent', + red: '#ff0000', + }, + }, + }, + ], + theme: { + extend: { + colors: { + black: 'black', + red: '#ee0000', + }, + backgroundColor: (theme) => theme('colors'), + }, + }, + corePlugins: ['backgroundColor'], + }, + ], + theme: { + extend: { colors: { white: 'white' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-black { + background-color: #000; + } + .bg-red { + background-color: #e00; + } + .bg-transparent { + background-color: #0000; + } + .bg-white { + background-color: #fff; + } + `) + }) +}) + +test('function presets can be mixed with object presets', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + () => ({ + presets: [], + theme: { + colors: { red: '#dd0000' }, + }, + }), + { + presets: [ + () => ({ + presets: [], + theme: { + colors: { + transparent: 'transparent', + red: '#ff0000', + }, + }, + }), + ], + theme: { + extend: { + colors: { + black: 'black', + red: '#ee0000', + }, + backgroundColor: (theme) => theme('colors'), + }, + }, + corePlugins: ['backgroundColor'], + }, + ], + theme: { + extend: { colors: { white: 'white' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-black { + background-color: #000; + } + .bg-red { + background-color: #e00; + } + .bg-transparent { + background-color: #0000; + } + .bg-white { + background-color: #fff; + } + `) + }) }) diff --git a/tests/dark-mode.test.js b/tests/dark-mode.test.js index ce06496b2..0c5273991 100644 --- a/tests/dark-mode.test.js +++ b/tests/dark-mode.test.js @@ -1,123 +1,121 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to use the darkMode "class" mode', () => { - let config = { - darkMode: 'class', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should be possible to use the darkMode "class" mode', () => { + let config = { + darkMode: 'class', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - :is(.dark .dark\:font-bold) { - font-weight: 700; - } - `) - }) - }) - - it('should be possible to change the class name', () => { - let config = { - darkMode: ['class', '.test-dark'], - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - :is(.test-dark .dark\:font-bold) { - font-weight: 700; - } - `) - }) - }) - - it('should be possible to use the darkMode "media" mode', () => { - let config = { - darkMode: 'media', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('should default to the `media` mode when no mode is provided', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('should default to the `media` mode when mode is set to `false`', () => { - let config = { - darkMode: false, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + :is(.dark .dark\:font-bold) { + font-weight: 700; + } + `) + }) +}) + +it('should be possible to change the class name', () => { + let config = { + darkMode: ['class', '.test-dark'], + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + :is(.test-dark .dark\:font-bold) { + font-weight: 700; + } + `) + }) +}) + +it('should be possible to use the darkMode "media" mode', () => { + let config = { + darkMode: 'media', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('should default to the `media` mode when no mode is provided', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('should default to the `media` mode when mode is set to `false`', () => { + let config = { + darkMode: false, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) }) }) diff --git a/tests/detect-nesting.test.js b/tests/detect-nesting.test.js index 39af6d422..08eeacf98 100644 --- a/tests/detect-nesting.test.js +++ b/tests/detect-nesting.test.js @@ -1,130 +1,128 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - it('should warn when we detect nested css', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should warn when we detect nested css', () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` - @tailwind utilities; + let input = css` + @tailwind utilities; - .nested { - .example { - } + .nested { + .example { } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - expect(result.messages).toMatchObject([ - { - type: 'warning', - text: [ - 'Nested CSS was detected, but CSS nesting has not been configured correctly.', - 'Please enable a CSS nesting plugin *before* Tailwind in your configuration.', - 'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting', - ].join('\n'), - }, - ]) - }) - }) - - it('should not warn when we detect nested css inside css @layer rules', () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) + expect(result.messages).toMatchObject([ + { + type: 'warning', + text: [ + 'Nested CSS was detected, but CSS nesting has not been configured correctly.', + 'Please enable a CSS nesting plugin *before* Tailwind in your configuration.', + 'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting', + ].join('\n'), + }, + ]) + }) +}) + +it('should not warn when we detect nested css inside css @layer rules', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @layer tw-base, tw-components, tw-utilities; + @layer tw-utilities { + @tailwind utilities; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` @layer tw-base, tw-components, tw-utilities; @layer tw-utilities { - @tailwind utilities; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @layer tw-base, tw-components, tw-utilities; - @layer tw-utilities { - .underline { - text-decoration-line: underline; - } - } - `) - expect(result.messages).toHaveLength(0) - }) - }) - - it('should warn when we detect namespaced @tailwind at rules', () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - .namespace { - @tailwind utilities; - } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - expect(result.messages).toMatchObject([ - { - type: 'warning', - text: [ - 'Nested @tailwind rules were detected, but are not supported.', - "Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix", - 'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy', - ].join('\n'), - }, - ]) - }) - }) - - it('should not warn when nesting a single rule inside a media query', () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind utilities; - - @media (min-width: 768px) { - .nested { + .underline { + text-decoration-line: underline; } } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(0) - expect(result.messages).toEqual([]) - }) + `) + expect(result.messages).toHaveLength(0) }) +}) - it('should only warn for the first detected nesting ', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should warn when we detect namespaced @tailwind at rules', () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` + let input = css` + .namespace { @tailwind utilities; + } + ` + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) + expect(result.messages).toMatchObject([ + { + type: 'warning', + text: [ + 'Nested @tailwind rules were detected, but are not supported.', + "Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix", + 'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy', + ].join('\n'), + }, + ]) + }) +}) + +it('should not warn when nesting a single rule inside a media query', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + + @media (min-width: 768px) { .nested { - .example { - } + } + } + ` - .other { - } + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(0) + expect(result.messages).toEqual([]) + }) +}) + +it('should only warn for the first detected nesting ', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + + .nested { + .example { } .other { - .example { - } } - ` + } - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - }) + .other { + .example { + } + } + ` + + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) }) }) diff --git a/tests/escapeClassName.test.js b/tests/escapeClassName.test.js index cdd834a79..7a8cd7b7b 100644 --- a/tests/escapeClassName.test.js +++ b/tests/escapeClassName.test.js @@ -1,8 +1,5 @@ import escapeClassName from '../src/util/escapeClassName' -import { crosscheck } from './util/run' -crosscheck(() => { - test('invalid characters are escaped', () => { - expect(escapeClassName('w:_$-1/2')).toEqual('w\\:_\\$-1\\/2') - }) +test('invalid characters are escaped', () => { + expect(escapeClassName('w:_$-1/2')).toEqual('w\\:_\\$-1\\/2') }) diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index e4085e03e..e6bf124b6 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -2,7 +2,7 @@ import fs from 'fs' import path from 'path' import postcss from 'postcss' import plugin from '../src/lib/evaluateTailwindFunctions' -import { crosscheck, run as runFull, html, css } from './util/run' +import { run as runFull, html, css } from './util/run' function run(input, opts = {}) { return postcss([ @@ -15,1373 +15,1377 @@ function run(input, opts = {}) { ]).process(input, { from: undefined }) } -crosscheck(({ stable, oxide }) => { - test('it looks up values in the theme using dot notation', () => { - let input = css` - .banana { - color: theme('colors.yellow'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using bracket notation', () => { - let input = css` - .banana { - color: theme('colors[yellow]'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using consecutive bracket notation', () => { - let input = css` - .banana { - color: theme('colors[yellow][100]'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: { - 100: '#f7cc50', - }, - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using bracket notation that have dots in them', () => { - let input = css` - .banana { - padding-top: theme('spacing[1.5]'); - } - ` - - let output = css` - .banana { - padding-top: 0.375rem; - } - ` - - return run(input, { - theme: { - spacing: { - '1.5': '0.375rem', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('theme with mismatched brackets throws an error ', async () => { - let config = { - theme: { - spacing: { - '1.5': '0.375rem', - }, - }, +test('it looks up values in the theme using dot notation', () => { + let input = css` + .banana { + color: theme('colors.yellow'); } + ` - let input = (path) => css` - .banana { - padding-top: theme('${path}'); - } - ` + let output = css` + .banana { + color: #f7cc50; + } + ` - await expect(run(input('spacing[1.5]]'), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[1.5]]` - ) - - await expect(run(input('spacing[[1.5]'), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[[1.5]` - ) - - await expect(run(input('spacing[a['), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[a[` - ) - }) - - test('color can be a function', () => { - let input = css` - .backgroundColor { - color: theme('backgroundColor.fn'); - } - .borderColor { - color: theme('borderColor.fn'); - } - .caretColor { - color: theme('caretColor.fn'); - } - .colors { - color: theme('colors.fn'); - } - .divideColor { - color: theme('divideColor.fn'); - } - .fill { - color: theme('fill.fn'); - } - .gradientColorStops { - color: theme('gradientColorStops.fn'); - } - .placeholderColor { - color: theme('placeholderColor.fn'); - } - .ringColor { - color: theme('ringColor.fn'); - } - .ringOffsetColor { - color: theme('ringOffsetColor.fn'); - } - .stroke { - color: theme('stroke.fn'); - } - .textColor { - color: theme('textColor.fn'); - } - ` - - let output = css` - .backgroundColor { - color: #f00; - } - .borderColor { - color: #f00; - } - .caretColor { - color: #f00; - } - .colors { - color: #f00; - } - .divideColor { - color: #f00; - } - .fill { - color: #f00; - } - .gradientColorStops { - color: #f00; - } - .placeholderColor { - color: #f00; - } - .ringColor { - color: #f00; - } - .ringOffsetColor { - color: #f00; - } - .stroke { - color: #f00; - } - .textColor { - color: #f00; - } - ` - - let fn = () => `#f00` - - return run(input, { - theme: { - backgroundColor: { fn }, - borderColor: { fn }, - caretColor: { fn }, - colors: { fn }, - divideColor: { fn }, - fill: { fn }, - gradientColorStops: { fn }, - placeholderColor: { fn }, - ringColor: { fn }, - ringOffsetColor: { fn }, - stroke: { fn }, - textColor: { fn }, + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) }) +}) - test('quotes are optional around the lookup path', () => { - let input = css` - .banana { - color: theme(colors.yellow); - } - ` +test('it looks up values in the theme using bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow]'); + } + ` - let output = css` - .banana { - color: #f7cc50; - } - ` + let output = css` + .banana { + color: #f7cc50; + } + ` - return run(input, { + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using consecutive bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow][100]'); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: { + 100: '#f7cc50', + }, + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using bracket notation that have dots in them', () => { + let input = css` + .banana { + padding-top: theme('spacing[1.5]'); + } + ` + + let output = css` + .banana { + padding-top: 0.375rem; + } + ` + + return run(input, { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('theme with mismatched brackets throws an error ', async () => { + let config = { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + } + + let input = (path) => css` + .banana { + padding-top: theme('${path}'); + } + ` + + await expect(run(input('spacing[1.5]]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[1.5]]` + ) + + await expect(run(input('spacing[[1.5]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[[1.5]` + ) + + await expect(run(input('spacing[a['), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[a[` + ) +}) + +test('color can be a function', () => { + let input = css` + .backgroundColor { + color: theme('backgroundColor.fn'); + } + .borderColor { + color: theme('borderColor.fn'); + } + .caretColor { + color: theme('caretColor.fn'); + } + .colors { + color: theme('colors.fn'); + } + .divideColor { + color: theme('divideColor.fn'); + } + .fill { + color: theme('fill.fn'); + } + .gradientColorStops { + color: theme('gradientColorStops.fn'); + } + .placeholderColor { + color: theme('placeholderColor.fn'); + } + .ringColor { + color: theme('ringColor.fn'); + } + .ringOffsetColor { + color: theme('ringOffsetColor.fn'); + } + .stroke { + color: theme('stroke.fn'); + } + .textColor { + color: theme('textColor.fn'); + } + ` + + let output = css` + .backgroundColor { + color: #f00; + } + .borderColor { + color: #f00; + } + .caretColor { + color: #f00; + } + .colors { + color: #f00; + } + .divideColor { + color: #f00; + } + .fill { + color: #f00; + } + .gradientColorStops { + color: #f00; + } + .placeholderColor { + color: #f00; + } + .ringColor { + color: #f00; + } + .ringOffsetColor { + color: #f00; + } + .stroke { + color: #f00; + } + .textColor { + color: #f00; + } + ` + + let fn = () => `#f00` + + return run(input, { + theme: { + backgroundColor: { fn }, + borderColor: { fn }, + caretColor: { fn }, + colors: { fn }, + divideColor: { fn }, + fill: { fn }, + gradientColorStops: { fn }, + placeholderColor: { fn }, + ringColor: { fn }, + ringOffsetColor: { fn }, + stroke: { fn }, + textColor: { fn }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('quotes are optional around the lookup path', () => { + let input = css` + .banana { + color: theme(colors.yellow); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('a default value can be provided', () => { + let input = css` + .cookieMonster { + color: theme('colors.blue', #0000ff); + } + ` + + let output = css` + .cookieMonster { + color: #0000ff; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('the default value can use the theme function', () => { + let input = css` + .cookieMonster { + color: theme('colors.blue', theme('colors.yellow')); + } + ` + + let output = css` + .cookieMonster { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('quotes are preserved around default values', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans', 'Helvetica Neue'); + } + ` + + let output = css` + .heading { + font-family: 'Helvetica Neue'; + } + ` + + return run(input, { + theme: { + fontFamily: { + serif: 'Constantia', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('an unquoted list is valid as a default value', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans', Helvetica, Arial, sans-serif); + } + ` + + let output = css` + .heading { + font-family: Helvetica, Arial, sans-serif; + } + ` + + return run(input, { + theme: { + fontFamily: { + serif: 'Constantia', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('a missing root theme value throws', () => { + let input = css` + .heading { + color: theme('colours.gray.100'); + } + ` + + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colours.gray.100' does not exist in your theme config. Your theme has the following top-level keys: 'colors'` + ) +}) - test('a default value can be provided', () => { - let input = css` - .cookieMonster { - color: theme('colors.blue', #0000ff); - } - ` +test('a missing nested theme property throws', () => { + let input = css` + .heading { + color: theme('colors.red'); + } + ` - let output = css` - .cookieMonster { - color: #0000ff; - } - ` + return expect( + run(input, { + theme: { + colors: { + blue: 'blue', + yellow: '#f7cc50', + }, + }, + }) + ).rejects.toThrowError( + `'colors.red' does not exist in your theme config. 'colors' has the following valid keys: 'blue', 'yellow'` + ) +}) - return run(input, { +test('a missing nested theme property with a close alternative throws with a suggestion', () => { + let input = css` + .heading { + color: theme('colors.yellw'); + } + ` + + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colors.yellw' does not exist in your theme config. Did you mean 'colors.yellow'?` + ) +}) - test('the default value can use the theme function', () => { - let input = css` - .cookieMonster { - color: theme('colors.blue', theme('colors.yellow')); - } - ` +test('a path through a non-object throws', () => { + let input = css` + .heading { + color: theme('colors.yellow.100'); + } + ` - let output = css` - .cookieMonster { - color: #f7cc50; - } - ` - - return run(input, { + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colors.yellow.100' does not exist in your theme config. 'colors.yellow' is not an object.` + ) +}) - test('quotes are preserved around default values', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans', 'Helvetica Neue'); - } - ` +test('a path which exists but is not a string throws', () => { + let input = css` + .heading { + color: theme('colors.yellow'); + } + ` - let output = css` - .heading { - font-family: 'Helvetica Neue'; - } - ` - - return run(input, { + return expect( + run(input, { theme: { - fontFamily: { - serif: 'Constantia', + colors: { + yellow: Symbol(), }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError(`'colors.yellow' was found but does not resolve to a string.`) +}) - test('an unquoted list is valid as a default value', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans', Helvetica, Arial, sans-serif); - } - ` +test('a path which exists but is invalid throws', () => { + let input = css` + .heading { + color: theme('colors'); + } + ` - let output = css` - .heading { - font-family: Helvetica, Arial, sans-serif; - } - ` - - return run(input, { + return expect( + run(input, { theme: { - fontFamily: { - serif: 'Constantia', + colors: {}, + }, + }) + ).rejects.toThrowError(`'colors' was found but does not resolve to a string.`) +}) + +test('a path which is an object throws with a suggested key', () => { + let input = css` + .heading { + color: theme('colors'); + } + ` + + return expect( + run(input, { + theme: { + colors: { + yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colors' was found but does not resolve to a string. Did you mean something like 'colors.yellow'?` + ) +}) - test('a missing root theme value throws', () => { - let input = css` - .heading { - color: theme('colours.gray.100'); - } - ` +test('array values are joined by default', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + } + ` - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colours.gray.100' does not exist in your theme config. Your theme has the following top-level keys: 'colors'` - ) - }) + let output = css` + .heading { + font-family: Inter, Helvetica, sans-serif; + } + ` - test('a missing nested theme property throws', () => { - let input = css` - .heading { - color: theme('colors.red'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - blue: 'blue', - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.red' does not exist in your theme config. 'colors' has the following valid keys: 'blue', 'yellow'` - ) - }) - - test('a missing nested theme property with a close alternative throws with a suggestion', () => { - let input = css` - .heading { - color: theme('colors.yellw'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.yellw' does not exist in your theme config. Did you mean 'colors.yellow'?` - ) - }) - - test('a path through a non-object throws', () => { - let input = css` - .heading { - color: theme('colors.yellow.100'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.yellow.100' does not exist in your theme config. 'colors.yellow' is not an object.` - ) - }) - - test('a path which exists but is not a string throws', () => { - let input = css` - .heading { - color: theme('colors.yellow'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: Symbol(), - }, - }, - }) - ).rejects.toThrowError(`'colors.yellow' was found but does not resolve to a string.`) - }) - - test('a path which exists but is invalid throws', () => { - let input = css` - .heading { - color: theme('colors'); - } - ` - - return expect( - run(input, { - theme: { - colors: {}, - }, - }) - ).rejects.toThrowError(`'colors' was found but does not resolve to a string.`) - }) - - test('a path which is an object throws with a suggested key', () => { - let input = css` - .heading { - color: theme('colors'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors' was found but does not resolve to a string. Did you mean something like 'colors.yellow'?` - ) - }) - - test('array values are joined by default', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - } - ` - - let output = css` - .heading { - font-family: Inter, Helvetica, sans-serif; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', 'Helvetica', 'sans-serif'], - }, + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', 'Helvetica', 'sans-serif'], }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) }) +}) - test('font sizes are retrieved without default line-heights or letter-spacing', () => { - let input = css` - .heading-1 { - font-size: theme('fontSize.lg'); - } - .heading-2 { - font-size: theme('fontSize.xl'); - } - ` +test('font sizes are retrieved without default line-heights or letter-spacing', () => { + let input = css` + .heading-1 { + font-size: theme('fontSize.lg'); + } + .heading-2 { + font-size: theme('fontSize.xl'); + } + ` - let output = css` - .heading-1 { - font-size: 20px; - } - .heading-2 { - font-size: 24px; - } - ` + let output = css` + .heading-1 { + font-size: 20px; + } + .heading-2 { + font-size: 24px; + } + ` - return run(input, { - theme: { - fontSize: { - lg: ['20px', '28px'], - xl: ['24px', { lineHeight: '32px', letterSpacing: '-0.01em' }], - }, + return run(input, { + theme: { + fontSize: { + lg: ['20px', '28px'], + xl: ['24px', { lineHeight: '32px', letterSpacing: '-0.01em' }], }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('outlines are retrieved without default outline-offset', () => { - let input = css` +test('outlines are retrieved without default outline-offset', () => { + let input = css` + .element { + outline: theme('outline.black'); + } + ` + + return run(input, { + theme: { + outline: { + black: ['2px dotted black', '4px'], + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` .element { - outline: theme('outline.black'); + outline: 2px dotted black; } - ` - - let output = css` - .element { - outline: 2px dotted #000; - } - ` - - return run(input, { - theme: { - outline: { - black: ['2px dotted black', '4px'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('font-family values are retrieved without font-variation-settings', () => { - let input = css` - .heading-1 { - font-family: theme('fontFamily.sans'); - } - .heading-2 { - font-family: theme('fontFamily.serif'); - } - .heading-3 { - font-family: theme('fontFamily.mono'); - } - ` +test('font-family values are retrieved without font-variation-settings', () => { + let input = css` + .heading-1 { + font-family: theme('fontFamily.sans'); + } + .heading-2 { + font-family: theme('fontFamily.serif'); + } + .heading-3 { + font-family: theme('fontFamily.mono'); + } + ` - let output = css` - .heading-1 { - font-family: Inter; - } - .heading-2 { - font-family: Times, serif; - } - .heading-3 { - font-family: Menlo, monospace; - } - ` + let output = css` + .heading-1 { + font-family: Inter; + } + .heading-2 { + font-family: Times, serif; + } + .heading-3 { + font-family: Menlo, monospace; + } + ` - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontVariationSettings: '"opsz" 32' }], - serif: [['Times', 'serif'], { fontVariationSettings: '"opsz" 32' }], - mono: ['Menlo, monospace', { fontVariationSettings: '"opsz" 32' }], - }, + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontVariationSettings: '"opsz" 32' }], + serif: [['Times', 'serif'], { fontVariationSettings: '"opsz" 32' }], + mono: ['Menlo, monospace', { fontVariationSettings: '"opsz" 32' }], }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('font-variation-settings values can be retrieved', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings'); - } - ` +test('font-variation-settings values can be retrieved', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings'); + } + ` - let output = css` + let output = css` + .heading { + font-family: Inter; + font-variation-settings: 'opsz' 32; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontVariationSettings: "'opsz' 32" }], + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-family values are joined when an array', () => { + let input = css` + .element { + font-family: theme('fontFamily.sans'); + } + ` + + let output = css` + .element { + font-family: Helvetica, Arial, sans-serif; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Helvetica', 'Arial', 'sans-serif'], + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-family values are retrieved without font-feature-settings', () => { + let input = css` + .heading-1 { + font-family: theme('fontFamily.sans'); + } + .heading-2 { + font-family: theme('fontFamily.serif'); + } + .heading-3 { + font-family: theme('fontFamily.mono'); + } + ` + + let output = css` + .heading-1 { + font-family: Inter; + } + .heading-2 { + font-family: Times, serif; + } + .heading-3 { + font-family: Menlo, monospace; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontFeatureSettings: '"cv11"' }], + serif: [['Times', 'serif'], { fontFeatureSettings: '"cv11"' }], + mono: ['Menlo, monospace', { fontFeatureSettings: '"cv11"' }], + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-feature-settings values can be retrieved', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings'); + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontFeatureSettings: "'cv11'" }], + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` .heading { font-family: Inter; - font-variation-settings: 'opsz' 32; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontVariationSettings: "'opsz' 32" }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-family values are joined when an array', () => { - let input = css` - .element { - font-family: theme('fontFamily.sans'); - } - ` - - let output = css` - .element { - font-family: Helvetica, Arial, sans-serif; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Helvetica', 'Arial', 'sans-serif'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-family values are retrieved without font-feature-settings', () => { - let input = css` - .heading-1 { - font-family: theme('fontFamily.sans'); - } - .heading-2 { - font-family: theme('fontFamily.serif'); - } - .heading-3 { - font-family: theme('fontFamily.mono'); - } - ` - - let output = css` - .heading-1 { - font-family: Inter; - } - .heading-2 { - font-family: Times, serif; - } - .heading-3 { - font-family: Menlo, monospace; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontFeatureSettings: '"cv11"' }], - serif: [['Times', 'serif'], { fontFeatureSettings: '"cv11"' }], - mono: ['Menlo, monospace', { fontFeatureSettings: '"cv11"' }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-feature-settings values can be retrieved', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings'); - } - ` - - let output = css` - .heading { font-feature-settings: 'cv11'; - font-family: Inter; } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontFeatureSettings: "'cv11'" }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('box-shadow values are joined when an array', () => { - let input = css` - .element { - box-shadow: theme('boxShadow.wtf'); - } - ` +test('box-shadow values are joined when an array', () => { + let input = css` + .element { + box-shadow: theme('boxShadow.wtf'); + } + ` - let output = css` - .element { - box-shadow: 0 0 2px #000, 1px 2px 3px #fff; - } - ` - - return run(input, { - theme: { - boxShadow: { - wtf: ['0 0 2px black', '1px 2px 3px white'], - }, + return run(input, { + theme: { + boxShadow: { + wtf: ['0 0 2px black', '1px 2px 3px white'], }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .element { + box-shadow: 0 0 2px black, 1px 2px 3px white; + } + `) + expect(result.warnings().length).toBe(0) }) +}) - test('transition-property values are joined when an array', () => { - let input = css` - .element { - transition-property: theme('transitionProperty.colors'); - } - ` +test('transition-property values are joined when an array', () => { + let input = css` + .element { + transition-property: theme('transitionProperty.colors'); + } + ` - let output = css` - .element { - transition-property: color, fill; - } - ` + let output = css` + .element { + transition-property: color, fill; + } + ` - return run(input, { - theme: { - transitionProperty: { - colors: ['color', 'fill'], - }, + return run(input, { + theme: { + transitionProperty: { + colors: ['color', 'fill'], }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('transition-duration values are joined when an array', () => { - let input = css` - .element { - transition-duration: theme('transitionDuration.lol'); - } - ` +test('transition-duration values are joined when an array', () => { + let input = css` + .element { + transition-duration: theme('transitionDuration.lol'); + } + ` - let output = css` - .element { - transition-duration: 1s, 2s; - } - ` + let output = css` + .element { + transition-duration: 1s, 2s; + } + ` - return run(input, { - theme: { - transitionDuration: { - lol: ['1s', '2s'], - }, + return run(input, { + theme: { + transitionDuration: { + lol: ['1s', '2s'], }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('basic screen function calls are expanded', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } +test('basic screen function calls are expanded', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; } - ` + } + ` - let output = css` + return run(input, { + theme: { screens: { sm: '600px' } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` @media (min-width: 600px) { .foo { color: red; } } - ` - - return run(input, { - theme: { screens: { sm: '600px' } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('screen function supports max-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } +test('screen function supports max-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; } - ` + } + ` - let output = css` - @media (max-width: 600px) { - .foo { - color: red; - } + let output = css` + @media (max-width: 600px) { + .foo { + color: red; } - ` + } + ` - return run(input, { - theme: { screens: { sm: { max: '600px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + return run(input, { + theme: { screens: { sm: { max: '600px' } } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('screen function supports min-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } +test('screen function supports min-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; } - ` + } + ` - let output = css` + return run(input, { + theme: { screens: { sm: { min: '600px' } } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` @media (min-width: 600px) { .foo { color: red; } } - ` - - return run(input, { - theme: { screens: { sm: { min: '600px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('screen function supports min-width and max-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } +test('screen function supports min-width and max-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; } - ` + } + ` - let output = css` + return run(input, { + theme: { screens: { sm: { min: '600px', max: '700px' } } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` @media (min-width: 600px) and (max-width: 700px) { .foo { color: red; } } - ` - - return run(input, { - theme: { screens: { sm: { min: '600px', max: '700px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('screen function supports raw screens', () => { - let input = css` - @media screen(mono) { - .foo { - color: red; - } +test('screen function supports raw screens', () => { + let input = css` + @media screen(mono) { + .foo { + color: red; } - ` + } + ` - let output = css` - @media monochrome { - .foo { - color: red; - } + let output = css` + @media monochrome { + .foo { + color: red; } - ` + } + ` - return run(input, { - theme: { screens: { mono: { raw: 'monochrome' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + return run(input, { + theme: { screens: { mono: { raw: 'monochrome' } } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('screen arguments can be quoted', () => { - let input = css` - @media screen('sm') { - .foo { - color: red; - } +test('screen arguments can be quoted', () => { + let input = css` + @media screen('sm') { + .foo { + color: red; } - ` + } + ` - let output = css` + return run(input, { + theme: { screens: { sm: '600px' } }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` @media (min-width: 600px) { .foo { color: red; } } - ` - - return run(input, { - theme: { screens: { sm: '600px' } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (1)', () => { - let input = css` +test('Theme function can extract alpha values for colors (1)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` .foo { - color: theme(colors.blue.500 / 50%); + color: rgb(59 130 246 / 50%); } - ` + `) + expect(result.warnings().length).toBe(0) + }) +}) - let output = css` +test('Theme function can extract alpha values for colors (2)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` .foo { - color: #3b82f680; + color: rgb(59 130 246 / 0.5); } - ` + `) + expect(result.warnings().length).toBe(0) + }) +}) - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, +test('Theme function can extract alpha values for colors (3)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (4)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + color: hsl(217 91% 60% / 50%); + } + `) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (2)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 0.5); - } - ` +test('Theme function can extract alpha values for colors (5)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` - let output = css` - .foo { - color: #3b82f680; - } - ` - - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + color: hsl(217 91% 60% / 0.5); + } + `) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (3)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` +test('Theme function can extract alpha values for colors (6)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` - let output = css` - .foo { - color: rgb(59 130 246 / var(--my-alpha)); - } - ` + let output = css` + .foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (4)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 50%); - } - ` +test('Theme function can extract alpha values for colors (7)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` - let output = css` - .foo { - color: #3c83f680; - } - ` + let output = css` + .foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` - return run(input, { - theme: { - colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, + return runFull(input, { + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (5)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 0.5); - } - ` +test('Theme function can extract alpha values for colors (8)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / theme(opacity.myalpha)); + } + ` - let output = css` - .foo { - color: #3c83f680; - } - ` + let output = css` + .foo { + color: rgb(var(--foo) / 50%); + } + ` - return run(input, { - theme: { - colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, + return runFull(input, { + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + + opacity: { + myalpha: '50%', + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (6)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` +test('Theme functions replace the alpha value placeholder even with no alpha provided', () => { + let input = css` + .foo { + background: theme(colors.blue.400); + color: theme(colors.blue.500); + } + ` - let output = css` - .foo { - color: hsl(217 91% 60% / var(--my-alpha)); - } - ` + let output = css` + .foo { + color: rgb(var(--foo) / 1); + background: #00f; + } + ` - return run(input, { - theme: { - colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, + return runFull(input, { + theme: { + colors: { + blue: { + 400: 'rgb(0 0 255 / )', + 500: 'rgb(var(--foo) / )', }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (7)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` +test('Theme functions can reference values with slashes in brackets', () => { + let input = css` + .foo1 { + color: theme(colors[a/b]); + } + .foo2 { + color: theme(colors[a/b]/50%); + } + ` - let output = css` - .foo { - color: rgb(var(--foo) / var(--my-alpha)); - } - ` + let output = css` + .foo1 { + color: #000; + } + .foo2 { + color: #00000080; + } + ` - return runFull(input, { - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, + return runFull(input, { + theme: { + colors: { + 'a/b': '#000000', }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme function can extract alpha values for colors (8)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / theme(opacity.myalpha)); - } - ` +test('Theme functions with alpha value inside quotes', () => { + let input = css` + .foo { + color: theme('colors.yellow / 50%'); + } + ` - let output = css` - .foo { - color: rgb(var(--foo) / 50%); - } - ` + let output = css` + .foo { + color: #f7cc5080; + } + ` - return runFull(input, { - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, - - opacity: { - myalpha: '50%', - }, + return runFull(input, { + theme: { + colors: { + yellow: '#f7cc50', }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme functions replace the alpha value placeholder even with no alpha provided', () => { - let input = css` - .foo { - background: theme(colors.blue.400); - color: theme(colors.blue.500); - } - ` +test('Theme functions with alpha with quotes value around color only', () => { + let input = css` + .foo { + color: theme('colors.yellow' / 50%); + } + ` - let output = css` - .foo { - color: rgb(var(--foo) / 1); - background: #00f; - } - ` + let output = css` + .foo { + color: #f7cc5080; + } + ` - return runFull(input, { - theme: { - colors: { - blue: { - 400: 'rgb(0 0 255 / )', - 500: 'rgb(var(--foo) / )', - }, - }, + return runFull(input, { + theme: { + colors: { + yellow: '#f7cc50', }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme functions can reference values with slashes in brackets', () => { - let input = css` - .foo1 { - color: theme(colors[a/b]); - } - .foo2 { - color: theme(colors[a/b]/50%); - } - ` +it('can find values with slashes in the theme key while still allowing for alpha values ', () => { + let input = css` + .foo00 { + color: theme(colors.foo-5); + } + .foo01 { + color: theme(colors.foo-5/10); + } + .foo02 { + color: theme(colors.foo-5/10/25); + } + .foo03 { + color: theme(colors.foo-5 / 10); + } + .foo04 { + color: theme(colors.foo-5/10 / 25); + } + ` - let output = css` - .foo1 { - color: #000; - } - .foo2 { - color: #00000080; - } - ` - - return runFull(input, { - theme: { - colors: { - 'a/b': '#000000', - }, + return runFull(input, { + theme: { + colors: { + 'foo-5': '#050000', + 'foo-5/10': '#051000', + 'foo-5/10/25': '#051025', }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme functions with alpha value inside quotes', () => { - let input = css` - .foo { - color: theme('colors.yellow / 50%'); - } - ` - - let output = css` - .foo { - color: #f7cc5080; - } - ` - - return runFull(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme functions with alpha with quotes value around color only', () => { - let input = css` - .foo { - color: theme('colors.yellow' / 50%); - } - ` - - let output = css` - .foo { - color: #f7cc5080; - } - ` - - return runFull(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - it('can find values with slashes in the theme key while still allowing for alpha values ', () => { - let input = css` + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` .foo00 { - color: theme(colors.foo-5); + color: #050000; } .foo01 { - color: theme(colors.foo-5/10); + color: #051000; } .foo02 { - color: theme(colors.foo-5/10/25); + color: #051025; } .foo03 { - color: theme(colors.foo-5 / 10); + color: #050000; } .foo04 { - color: theme(colors.foo-5/10 / 25); + color: #051000; + } + `) + }) +}) + +describe('context dependent', () => { + let configPath = path.resolve(__dirname, './evaluate-tailwind-functions.tailwind.config.js') + let filePath = path.resolve(__dirname, './evaluate-tailwind-functions.test.html') + let config = { + content: [filePath], + corePlugins: { preflight: false }, + } + + // Rebuild the config file for each test + beforeEach(() => fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`)) + afterEach(() => fs.promises.unlink(configPath)) + + test('should not generate when theme fn doesnt resolve', async () => { + await fs.promises.writeFile( + filePath, + html` +
+
+ ` + ) + + // TODO: We need a way to reuse the context in our test suite without requiring writing to files + // It should be an explicit thing tho — like we create a context and pass it in or something + let result = await runFull('@tailwind utilities', configPath) + + // 1. On first run it should work because it's been removed from the class cache + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + `) + + // 2. But we get a warning in the console + expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) + + // 3. The second run should work fine because it's been removed from the class cache + result = await runFull('@tailwind utilities', configPath) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + `) + + // 4. But we've not received any further logs about it + expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) + }) + + test('it works mayhaps', async () => { + let input = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*theme("spacing.4"))); + /* prettier-ignore */ + padding: calc(-1 * (2* theme("spacing.4"))); } ` - return runFull(input, { + let output = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*1rem)); + /* prettier-ignore */ + padding: calc(-1 * (2* 1rem)); + } + ` + + return run(input, { theme: { - colors: { - 'foo-5': '#050000', - 'foo-5/10': '#051000', - 'foo-5/10/25': '#051025', + spacing: { + 4: '1rem', }, }, }).then((result) => { - expect(result.css).toMatchCss(css` - .foo00 { - color: #050000; - } - .foo01 { - color: #051000; - } - .foo02 { - color: #051025; - } - .foo03 { - color: #050000; - } - .foo04 { - color: #051000; - } - `) - }) - }) - - describe('context dependent', () => { - let configPath = path.resolve(__dirname, './evaluate-tailwind-functions.tailwind.config.js') - let filePath = path.resolve(__dirname, './evaluate-tailwind-functions.test.html') - let config = { - content: [filePath], - corePlugins: { preflight: false }, - } - - // Rebuild the config file for each test - beforeEach(() => - fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) - ) - afterEach(() => fs.promises.unlink(configPath)) - - oxide.test.todo('should not generate when theme fn doesnt resolve') - stable.test('should not generate when theme fn doesnt resolve', async () => { - await fs.promises.writeFile( - filePath, - html` -
-
- ` - ) - - // TODO: We need a way to reuse the context in our test suite without requiring writing to files - // It should be an explicit thing tho — like we create a context and pass it in or something - let result = await runFull('@tailwind utilities', configPath) - - // 1. On first run it should work because it's been removed from the class cache - expect(result.css).toMatchCss(css` - .underline { - text-decoration-line: underline; - } - `) - - // 2. But we get a warning in the console - expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) - - // 3. The second run should work fine because it's been removed from the class cache - result = await runFull('@tailwind utilities', configPath) - - expect(result.css).toMatchCss(css` - .underline { - text-decoration-line: underline; - } - `) - - // 4. But we've not received any further logs about it - expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) }) }) }) diff --git a/tests/experimental.test.js b/tests/experimental.test.js index 3497783f9..b36141cb0 100644 --- a/tests/experimental.test.js +++ b/tests/experimental.test.js @@ -1,197 +1,195 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('experimental universal selector improvements (box-shadow)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('experimental universal selector improvements (box-shadow)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (pseudo hover)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .hover\:shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .hover\:shadow:hover { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (multiple classes: group)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .group-hover\:shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .group:hover .group-hover\:shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (child selectors: divide-y)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .resize { - resize: both; - } - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - test('experimental universal selector improvements (hover:divide-y)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .resize { - resize: both; - } - .hover\:divide-y:hover > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - test('experimental universal selector improvements (#app important)', () => { - let config = { - experimental: 'all', - important: '#app', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - #app :is(.resize) { - resize: both; - } - #app :is(.divide-y > :not([hidden]) ~ :not([hidden])) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - #app :is(.shadow) { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (pseudo hover)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .hover\:shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .hover\:shadow:hover { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (multiple classes: group)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group-hover\:shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .group:hover .group-hover\:shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (child selectors: divide-y)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .resize { + resize: both; + } + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +test('experimental universal selector improvements (hover:divide-y)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .resize { + resize: both; + } + .hover\:divide-y:hover > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +test('experimental universal selector improvements (#app important)', () => { + let config = { + experimental: 'all', + important: '#app', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + #app .resize { + resize: both; + } + #app :is(.divide-y > :not([hidden]) ~ :not([hidden])) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + #app .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) }) }) diff --git a/tests/extractor-edge-cases.test.js b/tests/extractor-edge-cases.test.js index 412702b35..83ca99e37 100644 --- a/tests/extractor-edge-cases.test.js +++ b/tests/extractor-edge-cases.test.js @@ -1,34 +1,32 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('PHP arrays', async () => { - let config = { - content: [ - { - raw: html`

">Hello world

`, - }, - ], - } +test('PHP arrays', async () => { + let config = { + content: [ + { + raw: html`

">Hello world

`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .max-w-\[16rem\] { - max-width: 16rem; - } - `) - }) - }) - - test('arbitrary values with quotes', async () => { - let config = { content: [{ raw: html`
` }] } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .content-\[\'hello\]\'\] { - --tw-content: 'hello]'; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .max-w-\[16rem\] { + max-width: 16rem; + } + `) + }) +}) + +test('arbitrary values with quotes', async () => { + let config = { content: [{ raw: html`
` }] } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .content-\[\'hello\]\'\] { + --tw-content: 'hello]'; + content: var(--tw-content); + } + `) }) }) diff --git a/tests/flattenColorPalette.test.js b/tests/flattenColorPalette.test.js index dae66e806..e8edcd9aa 100644 --- a/tests/flattenColorPalette.test.js +++ b/tests/flattenColorPalette.test.js @@ -1,84 +1,81 @@ -import { crosscheck } from './util/run' import flattenColorPalette from '../src/util/flattenColorPalette' -crosscheck(() => { - test('it flattens nested color objects', () => { - expect( - flattenColorPalette({ - purple: 'purple', - white: { - 25: 'rgba(255,255,255,.25)', - 50: 'rgba(255,255,255,.5)', - 75: 'rgba(255,255,255,.75)', - DEFAULT: '#fff', - }, - red: { - 1: 'rgb(33,0,0)', - 2: 'rgb(67,0,0)', - 3: 'rgb(100,0,0)', - }, - green: { - 1: 'rgb(0,33,0)', - 2: 'rgb(0,67,0)', - 3: 'rgb(0,100,0)', - }, - blue: { - 1: 'rgb(0,0,33)', - 2: 'rgb(0,0,67)', - 3: 'rgb(0,0,100)', - }, - }) - ).toEqual({ +test('it flattens nested color objects', () => { + expect( + flattenColorPalette({ purple: 'purple', - 'white-25': 'rgba(255,255,255,.25)', - 'white-50': 'rgba(255,255,255,.5)', - 'white-75': 'rgba(255,255,255,.75)', - white: '#fff', - 'red-1': 'rgb(33,0,0)', - 'red-2': 'rgb(67,0,0)', - 'red-3': 'rgb(100,0,0)', - 'green-1': 'rgb(0,33,0)', - 'green-2': 'rgb(0,67,0)', - 'green-3': 'rgb(0,100,0)', - 'blue-1': 'rgb(0,0,33)', - 'blue-2': 'rgb(0,0,67)', - 'blue-3': 'rgb(0,0,100)', + white: { + 25: 'rgba(255,255,255,.25)', + 50: 'rgba(255,255,255,.5)', + 75: 'rgba(255,255,255,.75)', + DEFAULT: '#fff', + }, + red: { + 1: 'rgb(33,0,0)', + 2: 'rgb(67,0,0)', + 3: 'rgb(100,0,0)', + }, + green: { + 1: 'rgb(0,33,0)', + 2: 'rgb(0,67,0)', + 3: 'rgb(0,100,0)', + }, + blue: { + 1: 'rgb(0,0,33)', + 2: 'rgb(0,0,67)', + 3: 'rgb(0,0,100)', + }, }) - }) - - test('it flattens deeply nested color objects', () => { - expect( - flattenColorPalette({ - primary: 'purple', - secondary: { - DEFAULT: 'blue', - hover: 'cyan', - focus: 'red', - }, - button: { - primary: { - DEFAULT: 'magenta', - hover: 'green', - focus: { - DEFAULT: 'yellow', - variant: 'orange', - }, - }, - }, - }) - ).toEqual({ - primary: 'purple', - secondary: 'blue', - 'secondary-hover': 'cyan', - 'secondary-focus': 'red', - 'button-primary': 'magenta', - 'button-primary-hover': 'green', - 'button-primary-focus': 'yellow', - 'button-primary-focus-variant': 'orange', - }) - }) - - test('it handles empty objects', () => { - expect(flattenColorPalette({})).toEqual({}) + ).toEqual({ + purple: 'purple', + 'white-25': 'rgba(255,255,255,.25)', + 'white-50': 'rgba(255,255,255,.5)', + 'white-75': 'rgba(255,255,255,.75)', + white: '#fff', + 'red-1': 'rgb(33,0,0)', + 'red-2': 'rgb(67,0,0)', + 'red-3': 'rgb(100,0,0)', + 'green-1': 'rgb(0,33,0)', + 'green-2': 'rgb(0,67,0)', + 'green-3': 'rgb(0,100,0)', + 'blue-1': 'rgb(0,0,33)', + 'blue-2': 'rgb(0,0,67)', + 'blue-3': 'rgb(0,0,100)', }) }) + +test('it flattens deeply nested color objects', () => { + expect( + flattenColorPalette({ + primary: 'purple', + secondary: { + DEFAULT: 'blue', + hover: 'cyan', + focus: 'red', + }, + button: { + primary: { + DEFAULT: 'magenta', + hover: 'green', + focus: { + DEFAULT: 'yellow', + variant: 'orange', + }, + }, + }, + }) + ).toEqual({ + primary: 'purple', + secondary: 'blue', + 'secondary-hover': 'cyan', + 'secondary-focus': 'red', + 'button-primary': 'magenta', + 'button-primary-hover': 'green', + 'button-primary-focus': 'yellow', + 'button-primary-focus-variant': 'orange', + }) +}) + +test('it handles empty objects', () => { + expect(flattenColorPalette({})).toEqual({}) +}) diff --git a/tests/format-variant-selector.test.js b/tests/format-variant-selector.test.js index 0cd0b05ff..3873f5d2d 100644 --- a/tests/format-variant-selector.test.js +++ b/tests/format-variant-selector.test.js @@ -1,363 +1,364 @@ import { finalizeSelector } from '../src/util/formatVariantSelector' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should be possible to add a simple variant to a simple selector', () => { - let selector = '.text-center' - let candidate = 'hover:text-center' +it('should be possible to add a simple variant to a simple selector', () => { + let selector = '.text-center' + let candidate = 'hover:text-center' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual('.hover\\:text-center:hover') +}) + +it('should be possible to add a multiple simple variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'focus:hover:text-center' + + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, + { format: '&:focus', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.focus\\:hover\\:text-center:hover:focus' + ) +}) + +it('should be possible to add a simple variant to a selector containing escaped parts', () => { + let selector = '.bg-\\[rgba\\(0\\,0\\,0\\)\\]' + let candidate = 'hover:bg-[rgba(0,0,0)]' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' + ) +}) + +it('should be possible to add a simple variant to a selector containing escaped parts (escape is slightly different)', () => { + let selector = '.bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]' + let candidate = 'hover:bg-[rgba(0,0,0)]' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' + ) +}) + +it('should be possible to add a simple variant to a more complex selector', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'hover:space-x-4' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple simple variants to a more complex selector', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'disabled:focus:hover:space-x-4' + + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, + { format: '&:focus', isArbitraryVariant: false }, + { format: '&:disabled', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.disabled\\:focus\\:hover\\:space-x-4:hover:focus:disabled > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add a single merge variant to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-hover:text-center' + + let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .group-hover\\:text-center' + ) +}) + +it('should be possible to add multiple merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-focus:group-hover:text-center' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:focus:hover .group-focus\\:group-hover\\:text-center' + ) +}) + +it('should be possible to add a single merge variant to a more complex selector', () => { + let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' + let candidate = 'group-hover:space-x-4' + + let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple merge variants to a more complex selector', () => { + let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' + let candidate = 'group-focus:group-hover:space-x-4' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:focus:hover .group-focus\\:group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple unique merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'peer-focus:group-hover:text-center' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.peer):focus ~ &' }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:focus ~ .group:hover .peer-focus\\:group-hover\\:text-center' + ) +}) + +it('should be possible to add multiple unique merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-hover:peer-focus:text-center' + + let formats = [ + { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .peer:focus ~ .group-hover\\:peer-focus\\:text-center' + ) +}) + +it('should be possible to use multiple :merge() calls with different "arguments"', () => { + let selector = '.foo' + let candidate = 'peer-focus:group-focus:peer-hover:group-hover:foo' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.peer):hover ~ &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:focus:hover ~ .group:focus:hover .peer-focus\\:group-focus\\:peer-hover\\:group-hover\\:foo' + ) +}) + +it('group hover and prose headings combination', () => { + let selector = '.text-center' + let candidate = 'group-hover:prose-headings:text-center' + let formats = [ + { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover :where(.group-hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4)' + ) +}) + +it('group hover and prose headings combination flipped', () => { + let selector = '.text-center' + let candidate = 'prose-headings:group-hover:text-center' + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + ':where(.group:hover .prose-headings\\:group-hover\\:text-center) :is(h1, h2, h3, h4)' + ) +}) + +it('should be possible to handle a complex utility', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'peer-disabled:peer-first-child:group-hover:group-focus:focus:hover:space-x-4' + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, // Hover + { format: '&:focus', isArbitraryVariant: false }, // Focus + { format: ':merge(.group):focus &', isArbitraryVariant: false }, // Group focus + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group hover + { format: ':merge(.peer):first-child ~ &', isArbitraryVariant: false }, // Peer first-child + { format: ':merge(.peer):disabled ~ &', isArbitraryVariant: false }, // Peer disabled + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:disabled:first-child ~ .group:hover:focus .peer-disabled\\:peer-first-child\\:group-hover\\:group-focus\\:focus\\:hover\\:space-x-4:hover:focus > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should match base utilities that are prefixed', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = 'tw-text-center' + let formats = [] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual('.tw-text-center') +}) + +it('should prefix classes from variants', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = 'foo:tw-text-center' + let formats = [{ format: '.foo &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( + '.tw-foo .foo\\:tw-text-center' + ) +}) + +it('should not prefix classes from arbitrary variants', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = '[.foo_&]:tw-text-center' + let formats = [{ format: '.foo &', isArbitraryVariant: true }] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( + '.foo .\\[\\.foo_\\&\\]\\:tw-text-center' + ) +}) + +it('Merged selectors with mixed combinators uses the first one', () => { + // This isn't explicitly specced behavior but it is how it works today + + let selector = '.text-center' + let candidate = 'text-center' + let formats = [ + { format: ':merge(.group):focus > &', isArbitraryVariant: true }, + { format: ':merge(.group):hover &', isArbitraryVariant: true }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover:focus > .text-center' + ) +}) + +describe('real examples', () => { + it('example a', () => { + let selector = '.placeholder-red-500::placeholder' + let candidate = 'hover:placeholder-red-500' let formats = [{ format: '&:hover', isArbitraryVariant: false }] - expect(finalizeSelector(selector, formats, { candidate })).toEqual('.hover\\:text-center:hover') + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:placeholder-red-500:hover::placeholder' + ) }) - it('should be possible to add a multiple simple variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'focus:hover:text-center' + it('example b', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'group-hover:hover:space-x-4' let formats = [ { format: '&:hover', isArbitraryVariant: false }, - { format: '&:focus', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.focus\\:hover\\:text-center:hover:focus' - ) - }) - - it('should be possible to add a simple variant to a selector containing escaped parts', () => { - let selector = '.bg-\\[rgba\\(0\\,0\\,0\\)\\]' - let candidate = 'hover:bg-[rgba(0,0,0)]' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' - ) - }) - - it('should be possible to add a simple variant to a selector containing escaped parts (escape is slightly different)', () => { - let selector = '.bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]' - let candidate = 'hover:bg-[rgba(0,0,0)]' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' - ) - }) - - it('should be possible to add a simple variant to a more complex selector', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'hover:space-x-4' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple simple variants to a more complex selector', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'disabled:focus:hover:space-x-4' - - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, - { format: '&:focus', isArbitraryVariant: false }, - { format: '&:disabled', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.disabled\\:focus\\:hover\\:space-x-4:hover:focus:disabled > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add a single merge variant to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-hover:text-center' - - let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:text-center' - ) - }) - - it('should be possible to add multiple merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-focus:group-hover:text-center' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:focus:hover .group-focus\\:group-hover\\:text-center' - ) - }) - - it('should be possible to add a single merge variant to a more complex selector', () => { - let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' - let candidate = 'group-hover:space-x-4' - - let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple merge variants to a more complex selector', () => { - let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' - let candidate = 'group-focus:group-hover:space-x-4' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:focus:hover .group-focus\\:group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple unique merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'peer-focus:group-hover:text-center' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.peer):focus ~ &' }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:focus ~ .group:hover .peer-focus\\:group-hover\\:text-center' - ) - }) - - it('should be possible to add multiple unique merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-hover:peer-focus:text-center' - - let formats = [ - { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, { format: ':merge(.group):hover &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .peer:focus ~ .group-hover\\:peer-focus\\:text-center' + '.group:hover .group-hover\\:hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' ) }) - it('should be possible to use multiple :merge() calls with different "arguments"', () => { - let selector = '.foo' - let candidate = 'peer-focus:group-focus:peer-hover:group-hover:foo' + it('should work for group-hover and class dark mode combinations', () => { + let selector = '.text-center' + let candidate = 'dark:group-hover:text-center' let formats = [ { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.peer):hover ~ &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + { format: '.dark &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:focus:hover ~ .group:focus:hover .peer-focus\\:group-focus\\:peer-hover\\:group-hover\\:foo' + '.dark .group:hover .dark\\:group-hover\\:text-center' ) }) - it('group hover and prose headings combination', () => { + it('should work for group-hover and class dark mode combinations (reversed)', () => { let selector = '.text-center' - let candidate = 'group-hover:prose-headings:text-center' + let candidate = 'group-hover:dark:text-center' + let formats = [ - { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + { format: '.dark &' }, + { format: ':merge(.group):hover &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover :where(.group-hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4)' + '.group:hover .dark .group-hover\\:dark\\:text-center' ) }) - it('group hover and prose headings combination flipped', () => { - let selector = '.text-center' - let candidate = 'prose-headings:group-hover:text-center' - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover - { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.group:hover .prose-headings\\:group-hover\\:text-center) :is(h1, h2, h3, h4)' - ) - }) - - it('should be possible to handle a complex utility', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'peer-disabled:peer-first-child:group-hover:group-focus:focus:hover:space-x-4' - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, // Hover - { format: '&:focus', isArbitraryVariant: false }, // Focus - { format: ':merge(.group):focus &', isArbitraryVariant: false }, // Group focus - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group hover - { format: ':merge(.peer):first-child ~ &', isArbitraryVariant: false }, // Peer first-child - { format: ':merge(.peer):disabled ~ &', isArbitraryVariant: false }, // Peer disabled - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:disabled:first-child ~ .group:hover:focus .peer-disabled\\:peer-first-child\\:group-hover\\:group-focus\\:focus\\:hover\\:space-x-4:hover:focus > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should match base utilities that are prefixed', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = 'tw-text-center' - let formats = [] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual('.tw-text-center') - }) - - it('should prefix classes from variants', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = 'foo:tw-text-center' - let formats = [{ format: '.foo &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( - '.tw-foo .foo\\:tw-text-center' - ) - }) - - it('should not prefix classes from arbitrary variants', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = '[.foo_&]:tw-text-center' - let formats = [{ format: '.foo &', isArbitraryVariant: true }] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( - '.foo .\\[\\.foo_\\&\\]\\:tw-text-center' - ) - }) - - it('Merged selectors with mixed combinators uses the first one', () => { - // This isn't explicitly specced behavior but it is how it works today - - let selector = '.text-center' - let candidate = 'text-center' - let formats = [ - { format: ':merge(.group):focus > &', isArbitraryVariant: true }, - { format: ':merge(.group):hover &', isArbitraryVariant: true }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover:focus > .text-center' - ) - }) - - describe('real examples', () => { - it('example a', () => { - let selector = '.placeholder-red-500::placeholder' - let candidate = 'hover:placeholder-red-500' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:placeholder-red-500:hover::placeholder' - ) - }) - - it('example b', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'group-hover:hover:space-x-4' - - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should work for group-hover and class dark mode combinations', () => { + describe('prose-headings', () => { + it('should be possible to use hover:prose-headings:text-center', () => { let selector = '.text-center' - let candidate = 'dark:group-hover:text-center' + let candidate = 'hover:prose-headings:text-center' - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: '.dark &', isArbitraryVariant: false }, - ] + let formats = [{ format: ':where(&) :is(h1, h2, h3, h4)' }, { format: '&:hover' }] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.dark .group:hover .dark\\:group-hover\\:text-center' + ':where(.hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4):hover' ) }) - it('should work for group-hover and class dark mode combinations (reversed)', () => { + it('should be possible to use prose-headings:hover:text-center', () => { let selector = '.text-center' - let candidate = 'group-hover:dark:text-center' + let candidate = 'prose-headings:hover:text-center' - let formats = [ - { format: '.dark &' }, - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - ] + let formats = [{ format: '&:hover' }, { format: ':where(&) :is(h1, h2, h3, h4)' }] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .dark .group-hover\\:dark\\:text-center' + ':where(.prose-headings\\:hover\\:text-center:hover) :is(h1, h2, h3, h4)' ) }) - - describe('prose-headings', () => { - it('should be possible to use hover:prose-headings:text-center', () => { - let selector = '.text-center' - let candidate = 'hover:prose-headings:text-center' - - let formats = [{ format: ':where(&) :is(h1, h2, h3, h4)' }, { format: '&:hover' }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4):hover' - ) - }) - - it('should be possible to use prose-headings:hover:text-center', () => { - let selector = '.text-center' - let candidate = 'prose-headings:hover:text-center' - - let formats = [{ format: '&:hover' }, { format: ':where(&) :is(h1, h2, h3, h4)' }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.prose-headings\\:hover\\:text-center:hover) :is(h1, h2, h3, h4)' - ) - }) - }) - }) - - describe('pseudo elements', () => { - it.each` - before | after - ${'&::before'} | ${'&::before'} - ${'&::before:hover'} | ${'&:hover::before'} - ${'&:before:hover'} | ${'&:hover:before'} - ${'&::file-selector-button:hover'} | ${'&::file-selector-button:hover'} - ${'&:hover::file-selector-button'} | ${'&:hover::file-selector-button'} - ${'.parent:hover &'} | ${'.parent:hover &'} - ${'.parent::before &'} | ${'.parent &::before'} - ${'.parent::before &:hover'} | ${'.parent &:hover::before'} - ${':where(&::before) :is(h1, h2, h3, h4)'} | ${':where(&) :is(h1, h2, h3, h4)::before'} - ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} | ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} - ${'#app :is(.dark &::before)'} | ${'#app :is(.dark &)::before'} - ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} - ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} - ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} - `('should translate "$before" into "$after"', ({ before, after }) => { - let result = finalizeSelector('.a', [{ format: before, isArbitraryVariant: false }], { - candidate: 'a', - }) - - expect(result).toEqual(after.replace('&', '.a')) - }) + }) +}) + +describe('pseudo elements', () => { + it.each` + before | after + ${'&::before'} | ${'&::before'} + ${'&::before:hover'} | ${'&:hover::before'} + ${'&:before:hover'} | ${'&:hover:before'} + ${'&::file-selector-button:hover'} | ${'&::file-selector-button:hover'} + ${'&:hover::file-selector-button'} | ${'&:hover::file-selector-button'} + ${'.parent:hover &'} | ${'.parent:hover &'} + ${'.parent::before &'} | ${'.parent &::before'} + ${'.parent::before &:hover'} | ${'.parent &:hover::before'} + ${':where(&::before) :is(h1, h2, h3, h4)'} | ${':where(&) :is(h1, h2, h3, h4)::before'} + ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} | ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} + ${'#app :is(.dark &::before)'} | ${'#app :is(.dark &)::before'} + ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} + ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} + ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.parent::marker li'} | ${'.parent li::marker'} + ${'.parent::selection li'} | ${'.parent li::selection'} + ${'.parent::placeholder input'} | ${'.parent input::placeholder'} + ${'.parent::backdrop dialog'} | ${'.parent dialog::backdrop'} + `('should translate "$before" into "$after"', ({ before, after }) => { + let result = finalizeSelector('.a', [{ format: before, isArbitraryVariant: false }], { + candidate: 'a', + }) + + expect(result).toEqual(after.replace('&', '.a')) }) }) diff --git a/tests/generate-rules.test.js b/tests/generate-rules.test.js index 3aa8592bc..57740c128 100644 --- a/tests/generate-rules.test.js +++ b/tests/generate-rules.test.js @@ -1,48 +1,46 @@ import { generateRules } from '../src/lib/generateRules' import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck, css } from './util/run' +import { css } from './util/run' -crosscheck(() => { - it('should not generate rules that are incorrect', () => { - let config = { - plugins: [ - ({ matchVariant }) => { - matchVariant('@', (value) => `@container (min-width: ${value})`) - }, - ], +it('should not generate rules that are incorrect', () => { + let config = { + plugins: [ + ({ matchVariant }) => { + matchVariant('@', (value) => `@container (min-width: ${value})`) + }, + ], + } + let context = createContext(resolveConfig(config)) + let rules = generateRules( + new Set([ + // Invalid, missing `-` + 'group[:hover]:underline', + + // Invalid, `-` should not be there + '@-[200px]:underline', + + // Valid + 'group-[:hover]:underline', + '@[200px]:underline', + ]), + context + ) + + // Ensure we only have 2 valid rules + expect(rules).toHaveLength(2) + + // Ensure we have the correct values + expect(rules[0][1].toString()).toMatchFormattedCss(css` + .group:hover .group-\[\:hover\]\:underline { + text-decoration-line: underline; } - let context = createContext(resolveConfig(config)) - let rules = generateRules( - new Set([ - // Invalid, missing `-` - 'group[:hover]:underline', - - // Invalid, `-` should not be there - '@-[200px]:underline', - - // Valid - 'group-[:hover]:underline', - '@[200px]:underline', - ]), - context - ) - - // Ensure we only have 2 valid rules - expect(rules).toHaveLength(2) - - // Ensure we have the correct values - expect(rules[0][1].toString()).toMatchFormattedCss(css` - .group:hover .group-\[\:hover\]\:underline { + `) + expect(rules[1][1].toString()).toMatchFormattedCss(css` + @container (min-width: 200px) { + .\@\[200px\]\:underline { text-decoration-line: underline; } - `) - expect(rules[1][1].toString()).toMatchFormattedCss(css` - @container (min-width: 200px) { - .\@\[200px\]\:underline { - text-decoration-line: underline; - } - } - `) - }) + } + `) }) diff --git a/tests/getClassList.test.js b/tests/getClassList.test.js index 671a767ec..63dfea88c 100644 --- a/tests/getClassList.test.js +++ b/tests/getClassList.test.js @@ -1,228 +1,225 @@ import resolveConfig from '../src/public/resolve-config' import plugin from '../src/public/create-plugin' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should generate every possible class, without variants', () => { - let config = {} +it('should generate every possible class, without variants', () => { + let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - expect(classes).toBeInstanceOf(Array) + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + expect(classes).toBeInstanceOf(Array) - // Verify we have a `container` for the 'components' section. - expect(classes).toContain('container') + // Verify we have a `container` for the 'components' section. + expect(classes).toContain('container') - // Verify we handle the DEFAULT case correctly - expect(classes).toContain('border') + // Verify we handle the DEFAULT case correctly + expect(classes).toContain('border') - // Verify we handle negative values correctly - expect(classes).toContain('-inset-1/4') - expect(classes).toContain('-m-0') - expect(classes).not.toContain('-uppercase') - expect(classes).not.toContain('-opacity-50') + // Verify we handle negative values correctly + expect(classes).toContain('-inset-1/4') + expect(classes).toContain('-m-0') + expect(classes).not.toContain('-uppercase') + expect(classes).not.toContain('-opacity-50') - config = { theme: { extend: { margin: { DEFAULT: '5px' } } } } - context = createContext(resolveConfig(config)) - classes = context.getClassList() + config = { theme: { extend: { margin: { DEFAULT: '5px' } } } } + context = createContext(resolveConfig(config)) + classes = context.getClassList() - expect(classes).not.toContain('-m-DEFAULT') - }) + expect(classes).not.toContain('-m-DEFAULT') +}) - it('should generate every possible class while handling negatives and prefixes', () => { - let config = { prefix: 'tw-' } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - expect(classes).toBeInstanceOf(Array) +it('should generate every possible class while handling negatives and prefixes', () => { + let config = { prefix: 'tw-' } + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + expect(classes).toBeInstanceOf(Array) - // Verify we have a `container` for the 'components' section. - expect(classes).toContain('tw-container') + // Verify we have a `container` for the 'components' section. + expect(classes).toContain('tw-container') - // Verify we handle the DEFAULT case correctly - expect(classes).toContain('tw-border') + // Verify we handle the DEFAULT case correctly + expect(classes).toContain('tw-border') - // Verify we handle negative values correctly - expect(classes).toContain('-tw-inset-1/4') - expect(classes).toContain('-tw-m-0') - expect(classes).not.toContain('-tw-uppercase') - expect(classes).not.toContain('-tw-opacity-50') + // Verify we handle negative values correctly + expect(classes).toContain('-tw-inset-1/4') + expect(classes).toContain('-tw-m-0') + expect(classes).not.toContain('-tw-uppercase') + expect(classes).not.toContain('-tw-opacity-50') - // These utilities do work but there's no reason to generate - // them alongside the `-{prefix}-{utility}` versions - expect(classes).not.toContain('tw--inset-1/4') - expect(classes).not.toContain('tw--m-0') + // These utilities do work but there's no reason to generate + // them alongside the `-{prefix}-{utility}` versions + expect(classes).not.toContain('tw--inset-1/4') + expect(classes).not.toContain('tw--m-0') - config = { - prefix: 'tw-', - theme: { extend: { margin: { DEFAULT: '5px' } } }, - } - context = createContext(resolveConfig(config)) - classes = context.getClassList() + config = { + prefix: 'tw-', + theme: { extend: { margin: { DEFAULT: '5px' } } }, + } + context = createContext(resolveConfig(config)) + classes = context.getClassList() - expect(classes).not.toContain('-tw-m-DEFAULT') - }) + expect(classes).not.toContain('-tw-m-DEFAULT') +}) - it('should not generate utilities with opacity by default', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() +it('should not generate utilities with opacity by default', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes).not.toContain('bg-red-500/50') - }) + expect(classes).not.toContain('bg-red-500/50') +}) - it('should not include metadata by default', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() +it('should not include metadata by default', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes.every((cls) => typeof cls === 'string')).toEqual(true) + expect(classes.every((cls) => typeof cls === 'string')).toEqual(true) - expect(classes).toContain('bg-red-500') - expect(classes).toContain('text-2xl') - }) + expect(classes).toContain('bg-red-500') + expect(classes).toContain('text-2xl') +}) - it('should generate utilities with modifier data when requested', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList({ includeMetadata: true }) +it('should generate utilities with modifier data when requested', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList({ includeMetadata: true }) - expect(classes).not.toContain('bg-red-500') - expect(classes).not.toContain('text-2xl') + expect(classes).not.toContain('bg-red-500') + expect(classes).not.toContain('text-2xl') - expect(classes).toContainEqual([ - 'bg-red-500', - { - modifiers: [ - '0', - '5', - '10', - '20', - '25', - '30', - '40', - '50', - '60', - '70', - '75', - '80', - '90', - '95', - '100', - ], - }, - ]) - expect(classes).toContainEqual([ - 'text-2xl', - { - modifiers: [ - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '10', - 'none', - 'tight', - 'snug', - 'normal', - 'relaxed', - 'loose', - ], - }, - ]) - }) - - it('should generate plugin-defined utilities with modifier data when requested', () => { - let config = { - plugins: [ - plugin(function ({ matchUtilities }) { - matchUtilities( - { - foo: (value) => { - return { margin: value } - }, - }, - { - values: { xl: '32px' }, - modifiers: { bar: 'something' }, - } - ) - matchUtilities( - { - 'foo-negative': (value) => { - return { margin: value } - }, - }, - { - values: { xl: '32px' }, - modifiers: { bar: 'something' }, - supportsNegativeValues: true, - } - ) - }), + expect(classes).toContainEqual([ + 'bg-red-500', + { + modifiers: [ + '0', + '5', + '10', + '20', + '25', + '30', + '40', + '50', + '60', + '70', + '75', + '80', + '90', + '95', + '100', ], - } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList({ includeMetadata: true }) - - expect(classes).toContainEqual(['foo-xl', { modifiers: ['bar'] }]) - expect(classes).toContainEqual(['foo-negative-xl', { modifiers: ['bar'] }]) - expect(classes).toContainEqual(['-foo-negative-xl', { modifiers: ['bar'] }]) - expect(classes).not.toContain('foo-xl') - expect(classes).not.toContain('-foo-xl') - expect(classes).not.toContainEqual(['-foo-xl', { modifiers: ['bar'] }]) - }) - - it('should not generate utilities with opacity even if safe-listed', () => { - let config = { - safelist: [ - { - pattern: /^bg-red-(400|500)(\/(40|50))?$/, - }, + }, + ]) + expect(classes).toContainEqual([ + 'text-2xl', + { + modifiers: [ + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + 'none', + 'tight', + 'snug', + 'normal', + 'relaxed', + 'loose', ], - } + }, + ]) +}) - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - - expect(classes).not.toContain('bg-red-500/50') - }) - - it('should not generate utilities that are set to undefined or null to so that they are removed', () => { - let config = { - theme: { - extend: { - colors: { - red: null, - green: undefined, - blue: { - 100: null, - 200: undefined, +it('should generate plugin-defined utilities with modifier data when requested', () => { + let config = { + plugins: [ + plugin(function ({ matchUtilities }) { + matchUtilities( + { + foo: (value) => { + return { margin: value } }, }, + { + values: { xl: '32px' }, + modifiers: { bar: 'something' }, + } + ) + matchUtilities( + { + 'foo-negative': (value) => { + return { margin: value } + }, + }, + { + values: { xl: '32px' }, + modifiers: { bar: 'something' }, + supportsNegativeValues: true, + } + ) + }), + ], + } + let context = createContext(resolveConfig(config)) + let classes = context.getClassList({ includeMetadata: true }) + + expect(classes).toContainEqual(['foo-xl', { modifiers: ['bar'] }]) + expect(classes).toContainEqual(['foo-negative-xl', { modifiers: ['bar'] }]) + expect(classes).toContainEqual(['-foo-negative-xl', { modifiers: ['bar'] }]) + expect(classes).not.toContain('foo-xl') + expect(classes).not.toContain('-foo-xl') + expect(classes).not.toContainEqual(['-foo-xl', { modifiers: ['bar'] }]) +}) + +it('should not generate utilities with opacity even if safe-listed', () => { + let config = { + safelist: [ + { + pattern: /^bg-red-(400|500)(\/(40|50))?$/, + }, + ], + } + + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + + expect(classes).not.toContain('bg-red-500/50') +}) + +it('should not generate utilities that are set to undefined or null to so that they are removed', () => { + let config = { + theme: { + extend: { + colors: { + red: null, + green: undefined, + blue: { + 100: null, + 200: undefined, + }, }, }, - safelist: [ - { - pattern: /^bg-(red|green|blue)-.*$/, - }, - ], - } + }, + safelist: [ + { + pattern: /^bg-(red|green|blue)-.*$/, + }, + ], + } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes).not.toContain('bg-red-100') // Red is `null` + expect(classes).not.toContain('bg-red-100') // Red is `null` - expect(classes).not.toContain('bg-green-100') // Green is `undefined` + expect(classes).not.toContain('bg-green-100') // Green is `undefined` - expect(classes).not.toContain('bg-blue-100') // Blue.100 is `null` - expect(classes).not.toContain('bg-blue-200') // Blue.200 is `undefined` + expect(classes).not.toContain('bg-blue-100') // Blue.100 is `null` + expect(classes).not.toContain('bg-blue-200') // Blue.200 is `undefined` - expect(classes).toContain('bg-blue-50') - expect(classes).toContain('bg-blue-300') - }) + expect(classes).toContain('bg-blue-50') + expect(classes).toContain('bg-blue-300') }) diff --git a/tests/getSortOrder.test.js b/tests/getSortOrder.test.js index 4526c4874..0863d268d 100644 --- a/tests/getSortOrder.test.js +++ b/tests/getSortOrder.test.js @@ -1,7 +1,6 @@ import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' import bigSign from '../src/util/bigSign' -import { crosscheck } from './util/run' /** * This is a function that the prettier-plugin-tailwindcss would use. It would @@ -25,121 +24,119 @@ function defaultSort(arrayOfTuples) { .join(' ') } -crosscheck(() => { - it('should return a list of tuples with the sort order', () => { - let input = 'font-bold underline hover:font-medium unknown' - let config = {} - let context = createContext(resolveConfig(config)) - expect(context.getClassOrder(input.split(' '))).toEqual([ - ['font-bold', expect.any(BigInt)], - ['underline', expect.any(BigInt)], - ['hover:font-medium', expect.any(BigInt)], +it('should return a list of tuples with the sort order', () => { + let input = 'font-bold underline hover:font-medium unknown' + let config = {} + let context = createContext(resolveConfig(config)) + expect(context.getClassOrder(input.split(' '))).toEqual([ + ['font-bold', expect.any(BigInt)], + ['underline', expect.any(BigInt)], + ['hover:font-medium', expect.any(BigInt)], - // Unknown values receive `null` - ['unknown', null], - ]) - }) + // Unknown values receive `null` + ['unknown', null], + ]) +}) - it.each([ - // Utitlies - ['px-3 p-1 py-3', 'p-1 px-3 py-3'], +it.each([ + // Utitlies + ['px-3 p-1 py-3', 'p-1 px-3 py-3'], - // Utitlies and components - ['px-4 container', 'container px-4'], + // Utitlies and components + ['px-4 container', 'container px-4'], - // Utilities with variants - ['px-3 focus:hover:p-3 hover:p-1 py-3', 'px-3 py-3 hover:p-1 focus:hover:p-3'], + // Utilities with variants + ['px-3 focus:hover:p-3 hover:p-1 py-3', 'px-3 py-3 hover:p-1 focus:hover:p-3'], - // Utitlies with important - ['px-3 !py-4', '!py-4 px-3'], - ['!py-4 px-3', '!py-4 px-3'], + // Utitlies with important + ['px-3 !py-4', '!py-4 px-3'], + ['!py-4 px-3', '!py-4 px-3'], - // Components with variants - ['hover:container container', 'container hover:container'], + // Components with variants + ['hover:container container', 'container hover:container'], - // Components and utilities with variants - [ - 'focus:hover:container hover:underline hover:container p-1', - 'p-1 hover:container focus:hover:container hover:underline', - ], + // Components and utilities with variants + [ + 'focus:hover:container hover:underline hover:container p-1', + 'p-1 hover:container focus:hover:container hover:underline', + ], - // Leave user css order alone, and move to the front - ['b p-1 a', 'b a p-1'], - ['hover:b focus:p-1 a', 'hover:b a focus:p-1'], + // Leave user css order alone, and move to the front + ['b p-1 a', 'b a p-1'], + ['hover:b focus:p-1 a', 'hover:b a focus:p-1'], - // Add special treatment for `group` and `peer` - ['a peer container underline', 'a peer container underline'], - ])('should sort "%s" based on the order we generate them in to "%s"', (input, output) => { - let config = {} + // Add special treatment for `group` and `peer` + ['a peer container underline', 'a peer container underline'], +])('should sort "%s" based on the order we generate them in to "%s"', (input, output) => { + let config = {} + let context = createContext(resolveConfig(config)) + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) +}) + +it.each([ + // Utitlies + ['tw-px-3 tw-p-1 tw-py-3', 'tw-p-1 tw-px-3 tw-py-3'], + + // Utitlies and components + ['tw-px-4 tw-container', 'tw-container tw-px-4'], + + // Utilities with variants + [ + 'tw-px-3 focus:hover:tw-p-3 hover:tw-p-1 tw-py-3', + 'tw-px-3 tw-py-3 hover:tw-p-1 focus:hover:tw-p-3', + ], + + // Utitlies with important + ['tw-px-3 !tw-py-4', '!tw-py-4 tw-px-3'], + ['!tw-py-4 tw-px-3', '!tw-py-4 tw-px-3'], + + // Components with variants + ['hover:tw-container tw-container', 'tw-container hover:tw-container'], + + // Components and utilities with variants + [ + 'focus:hover:tw-container hover:tw-underline hover:tw-container tw-p-1', + 'tw-p-1 hover:tw-container focus:hover:tw-container hover:tw-underline', + ], + + // Leave user css order alone, and move to the front + ['b tw-p-1 a', 'b a tw-p-1'], + ['hover:b focus:tw-p-1 a', 'hover:b a focus:tw-p-1'], + + // Add special treatment for `group` and `peer` + ['a tw-peer tw-container tw-underline', 'a tw-peer tw-container tw-underline'], +])( + 'should sort "%s" with prefixex based on the order we generate them in to "%s"', + (input, output) => { + let config = { prefix: 'tw-' } let context = createContext(resolveConfig(config)) expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - }) + } +) - it.each([ - // Utitlies - ['tw-px-3 tw-p-1 tw-py-3', 'tw-p-1 tw-px-3 tw-py-3'], - - // Utitlies and components - ['tw-px-4 tw-container', 'tw-container tw-px-4'], - - // Utilities with variants +it('sorts classes deterministically across multiple class lists', () => { + let classes = [ [ - 'tw-px-3 focus:hover:tw-p-3 hover:tw-p-1 tw-py-3', - 'tw-px-3 tw-py-3 hover:tw-p-1 focus:hover:tw-p-3', + 'a-class px-3 p-1 b-class py-3 bg-red-500 bg-blue-500', + 'a-class b-class bg-blue-500 bg-red-500 p-1 px-3 py-3', ], - - // Utitlies with important - ['tw-px-3 !tw-py-4', '!tw-py-4 tw-px-3'], - ['!tw-py-4 tw-px-3', '!tw-py-4 tw-px-3'], - - // Components with variants - ['hover:tw-container tw-container', 'tw-container hover:tw-container'], - - // Components and utilities with variants [ - 'focus:hover:tw-container hover:tw-underline hover:tw-container tw-p-1', - 'tw-p-1 hover:tw-container focus:hover:tw-container hover:tw-underline', + 'px-3 b-class p-1 py-3 bg-blue-500 a-class bg-red-500', + 'b-class a-class bg-blue-500 bg-red-500 p-1 px-3 py-3', ], + ] - // Leave user css order alone, and move to the front - ['b tw-p-1 a', 'b a tw-p-1'], - ['hover:b focus:tw-p-1 a', 'hover:b a focus:tw-p-1'], + let config = {} - // Add special treatment for `group` and `peer` - ['a tw-peer tw-container tw-underline', 'a tw-peer tw-container tw-underline'], - ])( - 'should sort "%s" with prefixex based on the order we generate them in to "%s"', - (input, output) => { - let config = { prefix: 'tw-' } - let context = createContext(resolveConfig(config)) - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - ) + // Same context, different class lists + let context = createContext(resolveConfig(config)) + for (const [input, output] of classes) { + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) + } - it('sorts classes deterministically across multiple class lists', () => { - let classes = [ - [ - 'a-class px-3 p-1 b-class py-3 bg-red-500 bg-blue-500', - 'a-class b-class bg-blue-500 bg-red-500 p-1 px-3 py-3', - ], - [ - 'px-3 b-class p-1 py-3 bg-blue-500 a-class bg-red-500', - 'b-class a-class bg-blue-500 bg-red-500 p-1 px-3 py-3', - ], - ] - - let config = {} - - // Same context, different class lists - let context = createContext(resolveConfig(config)) - for (const [input, output] of classes) { - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - - // Different context, different class lists - for (const [input, output] of classes) { - context = createContext(resolveConfig(config)) - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - }) + // Different context, different class lists + for (const [input, output] of classes) { + context = createContext(resolveConfig(config)) + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) + } }) diff --git a/tests/getVariants.test.js b/tests/getVariants.test.js index 8d79f8243..114d80824 100644 --- a/tests/getVariants.test.js +++ b/tests/getVariants.test.js @@ -2,188 +2,185 @@ import postcss from 'postcss' import selectorParser from 'postcss-selector-parser' import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should return a list of variants with meta information about the variant', () => { - let config = {} - let context = createContext(resolveConfig(config)) +it('should return a list of variants with meta information about the variant', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variants = context.getVariants() + let variants = context.getVariants() - expect(variants).toContainEqual({ - name: 'hover', - isArbitrary: false, - hasDash: true, - values: [], - selectors: expect.any(Function), - }) - - expect(variants).toContainEqual({ - name: 'group', - isArbitrary: true, - hasDash: true, - values: expect.any(Array), - selectors: expect.any(Function), - }) - - // `group-hover` now belongs to the `group` variant. The information exposed for the `group` - // variant is all you need. - expect(variants.find((v) => v.name === 'group-hover')).toBeUndefined() + expect(variants).toContainEqual({ + name: 'hover', + isArbitrary: false, + hasDash: true, + values: [], + selectors: expect.any(Function), }) - it('should provide selectors for simple variants', () => { - let config = {} - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === 'hover') - expect(variant.selectors()).toEqual(['&:hover']) + expect(variants).toContainEqual({ + name: 'group', + isArbitrary: true, + hasDash: true, + values: expect.any(Array), + selectors: expect.any(Function), }) - it('should provide selectors for parallel variants', () => { - let config = {} - let context = createContext(resolveConfig(config)) + // `group-hover` now belongs to the `group` variant. The information exposed for the `group` + // variant is all you need. + expect(variants.find((v) => v.name === 'group-hover')).toBeUndefined() +}) - let variants = context.getVariants() +it('should provide selectors for simple variants', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'marker') - expect(variant.selectors()).toEqual(['& *::marker', '&::marker']) - }) + let variants = context.getVariants() - it('should provide selectors for complex matchVariant variants like `group`', () => { - let config = {} - let context = createContext(resolveConfig(config)) + let variant = variants.find((v) => v.name === 'hover') + expect(variant.selectors()).toEqual(['&:hover']) +}) - let variants = context.getVariants() +it('should provide selectors for parallel variants', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'group') - expect(variant.selectors()).toEqual(['.group &']) - expect(variant.selectors({})).toEqual(['.group &']) - expect(variant.selectors({ value: 'hover' })).toEqual(['.group:hover &']) - expect(variant.selectors({ value: '.foo_&' })).toEqual(['.foo .group &']) - expect(variant.selectors({ modifier: 'foo', value: 'hover' })).toEqual(['.group\\/foo:hover &']) - expect(variant.selectors({ modifier: 'foo', value: '.foo_&' })).toEqual(['.foo .group\\/foo &']) - }) + let variants = context.getVariants() - it('should provide selectors for variants with atrules', () => { - let config = {} - let context = createContext(resolveConfig(config)) + let variant = variants.find((v) => v.name === 'marker') + expect(variant.selectors()).toEqual(['& *::marker', '&::marker']) +}) - let variants = context.getVariants() +it('should provide selectors for complex matchVariant variants like `group`', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'supports') - expect(variant.selectors({ value: 'display:grid' })).toEqual(['@supports (display:grid)']) - expect(variant.selectors({ value: 'aspect-ratio' })).toEqual([ - '@supports (aspect-ratio: var(--tw))', - ]) - }) + let variants = context.getVariants() - it('should provide selectors for custom plugins that do a combination of parallel variants with modifiers with arbitrary values and with atrules', () => { - let config = { - plugins: [ - function ({ matchVariant }) { - matchVariant('foo', (value, { modifier }) => { - return [ - ` + let variant = variants.find((v) => v.name === 'group') + expect(variant.selectors()).toEqual(['.group &']) + expect(variant.selectors({})).toEqual(['.group &']) + expect(variant.selectors({ value: 'hover' })).toEqual(['.group:hover &']) + expect(variant.selectors({ value: '.foo_&' })).toEqual(['.foo .group &']) + expect(variant.selectors({ modifier: 'foo', value: 'hover' })).toEqual(['.group\\/foo:hover &']) + expect(variant.selectors({ modifier: 'foo', value: '.foo_&' })).toEqual(['.foo .group\\/foo &']) +}) + +it('should provide selectors for variants with atrules', () => { + let config = {} + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === 'supports') + expect(variant.selectors({ value: 'display:grid' })).toEqual(['@supports (display:grid)']) + expect(variant.selectors({ value: 'aspect-ratio' })).toEqual([ + '@supports (aspect-ratio: var(--tw))', + ]) +}) + +it('should provide selectors for custom plugins that do a combination of parallel variants with modifiers with arbitrary values and with atrules', () => { + let config = { + plugins: [ + function ({ matchVariant }) { + matchVariant('foo', (value, { modifier }) => { + return [ + ` @supports (foo: ${modifier}) { - @media (width <= 400px) { + @media (max-width: 400px) { &:hover } } `, - `.${modifier}\\/${value} &:focus`, - ] - }) - }, - ], - } - let context = createContext(resolveConfig(config)) + `.${modifier}\\/${value} &:focus`, + ] + }) + }, + ], + } + let context = createContext(resolveConfig(config)) - let variants = context.getVariants() + let variants = context.getVariants() - let variant = variants.find((v) => v.name === 'foo') - expect(variant.selectors({ modifier: 'bar', value: 'baz' })).toEqual([ - '@supports (foo: bar) { @media (width <= 400px) { &:hover } }', - '.bar\\/baz &:focus', - ]) - }) - - it('should work for plugins that still use the modifySelectors API', () => { - let config = { - plugins: [ - function ({ addVariant }) { - addVariant('foo', ({ modifySelectors, container }) => { - // Manually mutating the selector - modifySelectors(({ selector }) => { - return selectorParser((selectors) => { - selectors.walkClasses((classNode) => { - classNode.value = `foo:${classNode.value}` - classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) - }) - }).processSync(selector) - }) - - // Manually wrap in supports query - let wrapper = postcss.atRule({ name: 'supports', params: 'display: grid' }) - let nodes = container.nodes - container.removeAll() - wrapper.append(nodes) - container.append(wrapper) - }) - }, - ], - } - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === 'foo') - expect(variant.selectors({})).toEqual(['@supports (display: grid) { .foo .foo\\:& }']) - }) - - it('should special case the `@`', () => { - let config = { - plugins: [ - ({ matchVariant }) => { - matchVariant( - '@', - (value, { modifier }) => `@container ${modifier ?? ''} (min-width: ${value})`, - { - modifiers: 'any', - values: { - xs: '20rem', - sm: '24rem', - md: '28rem', - lg: '32rem', - xl: '36rem', - '2xl': '42rem', - '3xl': '48rem', - '4xl': '56rem', - '5xl': '64rem', - '6xl': '72rem', - '7xl': '80rem', - }, - } - ) - }, - ], - } - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === '@') - expect(variant).toEqual({ - name: '@', - isArbitrary: true, - hasDash: false, - values: expect.any(Array), - selectors: expect.any(Function), - }) - expect(variant.selectors({ value: 'xs', modifier: 'foo' })).toEqual([ - '@container foo (min-width: 20rem)', - ]) - }) + let variant = variants.find((v) => v.name === 'foo') + expect(variant.selectors({ modifier: 'bar', value: 'baz' })).toEqual([ + '@supports (foo: bar) { @media (max-width: 400px) { &:hover } }', + '.bar\\/baz &:focus', + ]) +}) + +it('should work for plugins that still use the modifySelectors API', () => { + let config = { + plugins: [ + function ({ addVariant }) { + addVariant('foo', ({ modifySelectors, container }) => { + // Manually mutating the selector + modifySelectors(({ selector }) => { + return selectorParser((selectors) => { + selectors.walkClasses((classNode) => { + classNode.value = `foo:${classNode.value}` + classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) + }) + }).processSync(selector) + }) + + // Manually wrap in supports query + let wrapper = postcss.atRule({ name: 'supports', params: 'display: grid' }) + let nodes = container.nodes + container.removeAll() + wrapper.append(nodes) + container.append(wrapper) + }) + }, + ], + } + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === 'foo') + expect(variant.selectors({})).toEqual(['@supports (display: grid) { .foo .foo\\:& }']) +}) + +it('should special case the `@`', () => { + let config = { + plugins: [ + ({ matchVariant }) => { + matchVariant( + '@', + (value, { modifier }) => `@container ${modifier ?? ''} (min-width: ${value})`, + { + modifiers: 'any', + values: { + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + '7xl': '80rem', + }, + } + ) + }, + ], + } + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === '@') + expect(variant).toEqual({ + name: '@', + isArbitrary: true, + hasDash: false, + values: expect.any(Array), + selectors: expect.any(Function), + }) + expect(variant.selectors({ value: 'xs', modifier: 'foo' })).toEqual([ + '@container foo (min-width: 20rem)', + ]) }) diff --git a/tests/import-processing-a.css b/tests/import-processing-a.css new file mode 100644 index 000000000..65dd5f63a --- /dev/null +++ b/tests/import-processing-a.css @@ -0,0 +1 @@ +@tailwind utilities; diff --git a/tests/import-processing-b.css b/tests/import-processing-b.css new file mode 100644 index 000000000..69d5390f1 --- /dev/null +++ b/tests/import-processing-b.css @@ -0,0 +1,5 @@ +@layer utilities { + .foo { + color: red; + } +} diff --git a/tests/import-processing-c.css b/tests/import-processing-c.css new file mode 100644 index 000000000..508c10fe2 --- /dev/null +++ b/tests/import-processing-c.css @@ -0,0 +1,5 @@ +@tailwind utilities; + +.foo { + color: red; +} diff --git a/tests/import-processing-c.js b/tests/import-processing-c.js new file mode 100644 index 000000000..164503d5e --- /dev/null +++ b/tests/import-processing-c.js @@ -0,0 +1,9 @@ +module.exports = { + darkMode: 'class', + content: [ + { + raw: `
`, + }, + ], + corePlugins: { preflight: false }, +} diff --git a/tests/import-processing.test.js b/tests/import-processing.test.js new file mode 100644 index 000000000..ef59be348 --- /dev/null +++ b/tests/import-processing.test.js @@ -0,0 +1,76 @@ +import { html, css, run } from './util/run' + +describe('import processing', () => { + it('should be possible to import another css file', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @import './import-processing-a.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + `) + }) + + it('should be possible to import another css file after @tailwind directive', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + @import './import-processing-b.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + + .foo { + color: red; + } + `) + }) + + it('should be possible to add @config before @import statements', async () => { + let input = css` + @config "./import-processing-c.js"; + @import './import-processing-c.css'; + ` + + let result = await run(input) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + + .foo { + color: red; + } + `) + }) +}) diff --git a/tests/import-syntax.test.js b/tests/import-syntax.test.js index 992ef81d5..99f5163f7 100644 --- a/tests/import-syntax.test.js +++ b/tests/import-syntax.test.js @@ -1,129 +1,82 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('using @import instead of @tailwind', () => { - let config = { - content: [ - { - raw: html` -

Hello world!

-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addBase }) { - addBase({ - h1: { - fontSize: '32px', - }, - }) - }, - ], - } +test('using @import instead of @tailwind', () => { + let config = { + content: [ + { + raw: html` +

Hello world!

+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addBase }) { + addBase({ + h1: { + fontSize: '32px', + }, + }) + }, + ], + } - let input = css` - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; - ` + let input = css` + @import 'tailwindcss/base'; + @import 'tailwindcss/components'; + @import 'tailwindcss/utilities'; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - h1 { - font-size: 32px; - } - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + h1 { + font-size: 32px; + } + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .mt-6 { - margin-top: 1.5rem; - } - .bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - @media (min-width: 768px) { - .md\:hover\:text-center:hover { - text-align: center; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - h1 { - font-size: 32px; - } - ${defaults} + } + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + .mt-6 { + margin-top: 1.5rem; + } + .bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + @media (min-width: 768px) { + .md\:hover\:text-center:hover { + text-align: center; } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .mt-6 { - margin-top: 1.5rem; - } - .bg-black { - background-color: #000; - } - @media (min-width: 768px) { - .md\:hover\:text-center:hover { - text-align: center; - } - } - `) - }) + } + `) }) }) diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index 895ca053c..d66f21edc 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -2,230 +2,228 @@ import fs from 'fs' import path from 'path' import * as sharedState from '../src/lib/sharedState' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('important boolean', () => { - let config = { - important: true, - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents( - { - '.btn': { - button: 'yes', - }, +test('important boolean', () => { + let config = { + important: true, + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents( + { + '.btn': { + button: 'yes', }, - { respectImportant: true } - ) - addComponents( - { - '@font-face': { - 'font-family': 'Inter', - }, - '@page': { - margin: '1cm', - }, + }, + { respectImportant: true } + ) + addComponents( + { + '@font-face': { + 'font-family': 'Inter', }, - { respectImportant: true } - ) - addUtilities( - { - '.custom-util': { - button: 'no', - }, + '@page': { + margin: '1cm', }, - { respectImportant: false } - ) - }, - ], + }, + { respectImportant: true } + ) + addUtilities( + { + '.custom-util': { + button: 'no', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply font-bold; + } + .custom-important-component { + @apply text-center !important; + } } + @tailwind utilities; + ` - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply font-bold; - } - .custom-important-component { - @apply text-center !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { + .container { + max-width: 640px; } } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + .btn { + button: yes !important; + } + @font-face { + font-family: Inter; + } + @page { + margin: 1cm; + } + .custom-component { + font-weight: 700; + } + .custom-important-component { + text-align: center !important; + } + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .animate-spin { + animation: 1s linear infinite spin !important; + } + .font-bold { + font-weight: 700 !important; + } + .custom-util { + button: no; + } + .group:hover .group-hover\:focus-within\:text-left:focus-within { + text-align: left !important; + } + :is([dir='rtl'] .rtl\:active\:text-center:active) { + text-align: center !important; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:hover\:text-center:hover { + text-align: center !important; + } + } + :is(.dark .dark\:focus\:text-left:focus) { + text-align: left !important; + } + @media (min-width: 768px) { + .md\:hover\:text-right:hover { + text-align: right !important; + } + } + `) + }) +}) + +// This is in a describe block so we can use `afterEach` :) +describe('duplicate elision', () => { + let filePath = path.resolve(__dirname, './important-boolean-duplicates.test.html') + + afterEach(async () => await fs.promises.unlink(filePath)) + + test('important rules are not duplicated when rebuilding', async () => { + let config = { + important: true, + content: [filePath], + } + + await fs.promises.writeFile( + config.content[0], + html` +
+
+ ` + ) + + let input = css` @tailwind utilities; ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .container { - width: 100%; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .btn { - button: yes !important; - } - @font-face { - font-family: Inter; - } - @page { - margin: 1cm; - } - .custom-component { - font-weight: 700; - } - .custom-important-component { - text-align: center !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .animate-spin { - animation: 1s linear infinite spin !important; - } - .font-bold { - font-weight: 700 !important; - } - .custom-util { - button: no; - } - .group:hover .group-hover\:focus-within\:text-left:focus-within { - text-align: left !important; - } - :is([dir='rtl'] .rtl\:active\:text-center:active) { - text-align: center !important; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:hover\:text-center:hover { - text-align: center !important; - } - } - :is(.dark .dark\:focus\:text-left:focus) { - text-align: left !important; - } - @media (min-width: 768px) { - .md\:hover\:text-right:hover { - text-align: right !important; - } - } - `) - }) - }) + let result = await run(input, config) + let allContexts = Array.from(sharedState.contextMap.values()) - // This is in a describe block so we can use `afterEach` :) - describe('duplicate elision', () => { - let filePath = path.resolve(__dirname, './important-boolean-duplicates.test.html') + let context = allContexts[allContexts.length - 1] - afterEach(async () => await fs.promises.unlink(filePath)) + let ruleCacheSize1 = context.ruleCache.size - test('important rules are not duplicated when rebuilding', async () => { - let config = { - important: true, - content: [filePath], + expect(result.css).toMatchFormattedCss(css` + .ml-2 { + margin-left: 0.5rem !important; } + .ml-4 { + margin-left: 1rem !important; + } + `) - await fs.promises.writeFile( - config.content[0], - html` -
-
- ` - ) - - let input = css` - @tailwind utilities; + await fs.promises.writeFile( + config.content[0], + html` +
+
` + ) - let result = await run(input, config) - let allContexts = Array.from(sharedState.contextMap.values()) + result = await run(input, config) - let context = allContexts[allContexts.length - 1] + let ruleCacheSize2 = context.ruleCache.size - let ruleCacheSize1 = context.ruleCache.size + expect(result.css).toMatchFormattedCss(css` + .ml-2 { + margin-left: 0.5rem !important; + } + .ml-4 { + margin-left: 1rem !important; + } + .ml-6 { + margin-left: 1.5rem !important; + } + `) - expect(result.css).toMatchFormattedCss(css` - .ml-2 { - margin-left: 0.5rem !important; - } - .ml-4 { - margin-left: 1rem !important; - } - `) - - await fs.promises.writeFile( - config.content[0], - html` -
-
- ` - ) - - result = await run(input, config) - - let ruleCacheSize2 = context.ruleCache.size - - expect(result.css).toMatchFormattedCss(css` - .ml-2 { - margin-left: 0.5rem !important; - } - .ml-4 { - margin-left: 1rem !important; - } - .ml-6 { - margin-left: 1.5rem !important; - } - `) - - // The rule cache was effectively doubling in size previously - // because the rule cache was never de-duped - // This ensures this behavior doesn't return - expect(ruleCacheSize2 - ruleCacheSize1).toBeLessThan(10) - }) + // The rule cache was effectively doubling in size previously + // because the rule cache was never de-duped + // This ensures this behavior doesn't return + expect(ruleCacheSize2 - ruleCacheSize1).toBeLessThan(10) }) }) diff --git a/tests/important-modifier-prefix.test.js b/tests/important-modifier-prefix.test.js index 782ec809e..2c6a8bb62 100644 --- a/tests/important-modifier-prefix.test.js +++ b/tests/important-modifier-prefix.test.js @@ -1,79 +1,77 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('important modifier with prefix', () => { - let config = { - important: false, - prefix: 'tw-', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
`, - }, - ], - corePlugins: { preflight: false }, - } +test('important modifier with prefix', () => { + let config = { + important: false, + prefix: 'tw-', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\!tw-container { + width: 100% !important; + } + @media (min-width: 640px) { .\!tw-container { - width: 100% !important; + max-width: 640px !important; } - @media (min-width: 640px) { - .\!tw-container { - max-width: 640px !important; - } + } + @media (min-width: 768px) { + .\!tw-container { + max-width: 768px !important; } - @media (min-width: 768px) { - .\!tw-container { - max-width: 768px !important; - } + } + @media (min-width: 1024px) { + .\!tw-container { + max-width: 1024px !important; } - @media (min-width: 1024px) { - .\!tw-container { - max-width: 1024px !important; - } + } + @media (min-width: 1280px) { + .\!tw-container { + max-width: 1280px !important; } - @media (min-width: 1280px) { - .\!tw-container { - max-width: 1280px !important; - } + } + @media (min-width: 1536px) { + .\!tw-container { + max-width: 1536px !important; } - @media (min-width: 1536px) { - .\!tw-container { - max-width: 1536px !important; - } + } + .\!tw-font-bold { + font-weight: 700 !important; + } + .hover\:\!tw-text-center:hover { + text-align: center !important; + } + @media (min-width: 1024px) { + .lg\:\!tw-opacity-50 { + opacity: 0.5 !important; } - .\!tw-font-bold { - font-weight: 700 !important; + } + @media (min-width: 1280px) { + .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { + float: right !important; } - .hover\:\!tw-text-center:hover { - text-align: center !important; - } - @media (min-width: 1024px) { - .lg\:\!tw-opacity-50 { - opacity: 0.5 !important; - } - } - @media (min-width: 1280px) { - .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { - float: right !important; - } - } - `) - }) + } + `) }) }) diff --git a/tests/important-modifier.test.js b/tests/important-modifier.test.js index 6d30fd0bc..fe4e14b33 100644 --- a/tests/important-modifier.test.js +++ b/tests/important-modifier.test.js @@ -1,153 +1,149 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('important modifier', () => { - let config = { - important: false, - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ theme, matchUtilities, addComponents }) { - matchUtilities( - { - 'custom-parent': (value) => { - return { - '.custom-child': { - margin: value, - }, - } - }, +test('important modifier', () => { + let config = { + important: false, + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ theme, matchUtilities, addComponents }) { + matchUtilities( + { + 'custom-parent': (value) => { + return { + '.custom-child': { + margin: value, + }, + } }, - { values: theme('spacing') } - ) - addComponents({ - '.btn': { - '&.disabled, &:disabled': { - color: 'gray', - }, + }, + { values: theme('spacing') } + ) + addComponents({ + '.btn': { + '&.disabled, &:disabled': { + color: 'gray', }, - }) - }, - ], - } + }, + }) + }, + ], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!container { + width: 100% !important; + } + @media (min-width: 640px) { .\!container { - width: 100% !important; + max-width: 640px !important; } - @media (min-width: 640px) { - .\!container { - max-width: 640px !important; - } + } + @media (min-width: 768px) { + .\!container { + max-width: 768px !important; } - @media (min-width: 768px) { - .\!container { - max-width: 768px !important; - } + } + @media (min-width: 1024px) { + .\!container { + max-width: 1024px !important; } - @media (min-width: 1024px) { - .\!container { - max-width: 1024px !important; - } + } + @media (min-width: 1280px) { + .\!container { + max-width: 1280px !important; } - @media (min-width: 1280px) { - .\!container { - max-width: 1280px !important; - } + } + @media (min-width: 1536px) { + .\!container { + max-width: 1536px !important; } - @media (min-width: 1536px) { - .\!container { - max-width: 1536px !important; - } + } + .btn.disabled, + .btn:disabled { + color: gray; + } + .btn.\!disabled { + color: gray !important; + } + .\!font-bold { + font-weight: 700 !important; + } + .\!custom-parent-5 .custom-child { + margin: 1.25rem !important; + } + .hover\:\!text-center:hover { + text-align: center !important; + } + @media (min-width: 1024px) { + .lg\:\!opacity-50 { + opacity: 0.5 !important; } - .btn.disabled, - .btn:disabled { - color: gray; + } + @media (min-width: 1280px) { + .xl\:focus\:disabled\:\!float-right:disabled:focus { + float: right !important; } - .btn.\!disabled { - color: gray !important; - } - .\!font-bold { - font-weight: 700 !important; - } - .\!custom-parent-5 .custom-child { - margin: 1.25rem !important; - } - .hover\:\!text-center:hover { - text-align: center !important; - } - @media (min-width: 1024px) { - .lg\:\!opacity-50 { - opacity: 0.5 !important; - } - } - @media (min-width: 1280px) { - .xl\:focus\:disabled\:\!float-right:disabled:focus { - float: right !important; - } - } - `) - }) - }) - - test('the important modifier works on utilities using :where()', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents }) { - addComponents({ - ':where(.btn)': { - backgroundColor: '#00f', - }, - }) - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :where(.\!btn) { - background-color: #00f !important; - } - :where(.btn) { - background-color: #00f; - } - :where(.hover\:btn:hover) { - background-color: #00f; - } - :where(.hover\:focus\:disabled\:\!btn:disabled:focus:hover) { - background-color: #00f !important; - } - `) - }) + } + `) + }) +}) + +test('the important modifier works on utilities using :where()', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents }) { + addComponents({ + ':where(.btn)': { + backgroundColor: '#00f', + }, + }) + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :where(.\!btn) { + background-color: #00f !important; + } + :where(.btn), + :where(.hover\:btn:hover) { + background-color: #00f; + } + :where(.hover\:focus\:disabled\:\!btn:disabled:focus:hover) { + background-color: #00f !important; + } + `) }) }) diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index 22edafb94..1ec20922c 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -1,205 +1,202 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('important selector', () => { - let config = { - important: '#app', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents( - { - '.btn': { - button: 'yes', - }, +test('important selector', () => { + let config = { + important: '#app', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents( + { + '.btn': { + button: 'yes', }, - { respectImportant: true } - ) - addComponents( - { - '@font-face': { - 'font-family': 'Inter', - }, - '@page': { - margin: '1cm', - }, + }, + { respectImportant: true } + ) + addComponents( + { + '@font-face': { + 'font-family': 'Inter', }, - { respectImportant: true } - ) - addUtilities( - { - '.custom-util': { - button: 'no', - }, + '@page': { + margin: '1cm', }, - { respectImportant: false } - ) - }, - ], + }, + { respectImportant: true } + ) + addUtilities( + { + '.custom-util': { + button: 'no', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply font-bold; + } + .custom-important-component { + @apply text-center !important; + } } + @tailwind utilities; + ` - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply font-bold; - } - .custom-important-component { - @apply text-center !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { + .container { + max-width: 640px; } } - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + #app .btn { + button: yes; + } + @font-face { + font-family: Inter; + } + @page { + margin: 1cm; + } + .custom-component { + font-weight: 700; + } + .custom-important-component { + text-align: center !important; + } + @keyframes spin { + to { + transform: rotate(360deg); } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - #app .btn { - button: yes; - } - @font-face { - font-family: Inter; - } - @page { - margin: 1cm; - } - .custom-component { - font-weight: 700; - } - .custom-important-component { - text-align: center !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - #app :is(.animate-spin) { - animation: 1s linear infinite spin; - } - #app :is(.font-bold) { - font-weight: 700; - } - .custom-util { - button: no; - } - #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { - text-align: left; - } - #app :is(:is([dir='rtl'] .rtl\:active\:text-center:active)) { + } + #app .animate-spin { + animation: 1s linear infinite spin; + } + #app .font-bold { + font-weight: 700; + } + .custom-util { + button: no; + } + #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { + text-align: left; + } + #app :is([dir='rtl'] .rtl\:active\:text-center:active) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + #app .motion-safe\:hover\:text-center:hover { text-align: center; } - @media (prefers-reduced-motion: no-preference) { - #app :is(.motion-safe\:hover\:text-center:hover) { - text-align: center; - } + } + #app :is(.dark .dark\:before\:underline):before { + content: var(--tw-content); + text-decoration-line: underline; + } + #app :is(.dark .dark\:focus\:text-left:focus) { + text-align: left; + } + @media (min-width: 768px) { + #app .md\:hover\:text-right:hover { + text-align: right; } - #app :is(.dark .dark\:before\:underline):before { - content: var(--tw-content); - text-decoration-line: underline; - } - #app :is(:is(.dark .dark\:focus\:text-left:focus)) { - text-align: left; - } - @media (min-width: 768px) { - #app :is(.md\:hover\:text-right:hover) { - text-align: right; - } - } - #app - :is( - [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) - )::file-selector-button:hover { - background-color: #000; - } - `) - }) - }) - - test('pseudo-elements are appended after the `:is()`', () => { - let config = { - important: '#app', - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - #app :is(.dark .dark\:before\:bg-black)::before { - content: var(--tw-content); - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - #app :is(.dark .dark\:before\:bg-black)::before { - content: var(--tw-content); - background-color: #000; - } - `) - }) + } + #app + :-webkit-any( + [dir='rtl'] + :-webkit-any(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + )::-webkit-file-upload-button:hover { + background-color: #000; + } + #app + :is( + [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + )::file-selector-button:hover { + background-color: #000; + } + `) + }) +}) + +test('pseudo-elements are appended after the `:-webkit-any()`', () => { + let config = { + important: '#app', + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + #app :is(.dark .dark\:before\:flex):before { + content: var(--tw-content); + display: flex; + } + `) }) }) diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index 3b02c8966..b025f8625 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -1,1374 +1,834 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('it works', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+test('it works', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- - `, + things: Array /* PropType */, + }, + setup: () => { + const count = ref(0) + // Weird regex-looking stuff that once caused a stack overflow in candidatePermutations + const pattern = ' ]-[] ' + return { + count, + stuff: [] /* string[] | undefined */, + } + }, + }) + + `, + }, + ], + corePlugins: { preflight: false }, + theme: { + extend: { + screens: { + range: { min: '1280px', max: '1535px' }, + multi: [{ min: '640px', max: '767px' }, { max: '868px' }], }, - ], - corePlugins: { preflight: false }, - theme: { - extend: { - screens: { - range: { min: '1280px', max: '1535px' }, - multi: [{ min: '640px', max: '767px' }, { max: '868px' }], - }, - gradientColorStops: { - foo: '#bada55', - }, - backgroundImage: { - 'hero--home-1': "url('/images/homepage-1.jpg')", - }, + gradientColorStops: { + foo: '#bada55', + }, + backgroundImage: { + 'hero--home-1': "url('/images/homepage-1.jpg')", }, }, - plugins: [ - function ({ addVariant }) { - addVariant( - 'foo', - ({ container }) => { - container.walkRules((rule) => { - rule.selector = `.foo\\:${rule.selector.slice(1)}` - rule.walkDecls((decl) => { - decl.important = true - }) + }, + plugins: [ + function ({ addVariant }) { + addVariant( + 'foo', + ({ container }) => { + container.walkRules((rule) => { + rule.selector = `.foo\\:${rule.selector.slice(1)}` + rule.walkDecls((decl) => { + decl.important = true }) + }) + }, + { before: 'sm' } + ) + }, + function ({ addUtilities, addBase, theme }) { + addBase({ + h1: { + fontSize: theme('fontSize.2xl'), + fontWeight: theme('fontWeight.bold'), + '&:first-child': { + marginTop: '0px', }, - { before: 'sm' } - ) - }, - function ({ addUtilities, addBase, theme }) { - addBase({ - h1: { - fontSize: theme('fontSize.2xl'), - fontWeight: theme('fontWeight.bold'), - '&:first-child': { - marginTop: '0px', - }, + }, + }) + addUtilities( + { + '.magic-none': { + magic: 'none', }, - }) - addUtilities( - { - '.magic-none': { - magic: 'none', - }, - '.magic-tons': { - magic: 'tons', - }, + '.magic-tons': { + magic: 'tons', }, - ['responsive', 'hover'] - ) - }, - ], - } + }, + ['responsive', 'hover'] + ) + }, + ], + } - let input = css` - @layer utilities { - .custom-util { - background: #abcdef; - } - *, - ::before, - ::after, - ::backdrop { - margin: 10px; - } + let input = css` + @layer utilities { + .custom-util { + background: #abcdef; } - @layer components { - .test-apply-font-variant { - @apply ordinal tabular-nums; - } - .custom-component { - background: #123456; - } - *, - ::before, - ::after, - ::backdrop { - padding: 5px; - } - .foo .bg-black { - appearance: none; - } + *, + ::before, + ::after, + ::backdrop { + margin: 10px; } - @layer base { - div { - background: #654321; - } + } + @layer components { + .test-apply-font-variant { + @apply ordinal tabular-nums; } + .custom-component { + background: #123456; + } + *, + ::before, + ::after, + ::backdrop { + padding: 5px; + } + .foo .bg-black { + appearance: none; + } + } + @layer base { + div { + background: #654321; + } + } + .theme-test { + font-family: theme('fontFamily.sans'); + color: theme('colors.blue.500'); + } + @screen lg { + .screen-test { + color: purple; + } + } + .apply-1 { + @apply mt-6; + } + .apply-2 { + @apply mt-6; + } + .apply-test { + @apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200; + } + .apply-components { + @apply container mx-auto; + } + .drop-empty-rules { + @apply hover:font-bold; + } + .apply-group { + @apply group-hover:font-bold; + } + .apply-dark-mode { + @apply dark:font-bold; + } + .apply-with-existing:hover { + @apply font-normal sm:bg-green-500; + } + .multiple, + .selectors { + @apply font-bold group-hover:font-normal; + } + .list { + @apply space-y-4; + } + .nested { + .example { + @apply font-bold hover:font-normal; + } + } + .apply-order-a { + @apply m-5 mt-6; + } + .apply-order-b { + @apply m-5 mt-6; + } + .apply-dark-group-example-a { + @apply dark:group-hover:bg-green-500; + } + .crazy-example { + @apply sm:motion-safe:group-active:focus:opacity-10; + } + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` .theme-test { - font-family: theme('fontFamily.sans'); - color: theme('colors.blue.500'); + color: #3b82f6; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, + Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, + Segoe UI Symbol, Noto Color Emoji; } - @screen lg { + @media (min-width: 1024px) { .screen-test { color: purple; } } - .apply-1 { - @apply mt-6; - } + .apply-1, .apply-2 { - @apply mt-6; + margin-top: 1.5rem; } .apply-test { - @apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200; + --tw-bg-opacity: 1; + background-color: rgb(236 72 153 / var(--tw-bg-opacity)); + margin-top: 1.5rem; + } + .apply-test:hover, + .apply-test:hover:focus { + font-weight: 700; + } + @media (min-width: 640px) { + .apply-test { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } + .apply-test:nth-child(2n):focus { + --tw-bg-opacity: 1; + background-color: rgb(251 207 232 / var(--tw-bg-opacity)); + } } .apply-components { - @apply container mx-auto; + width: 100%; } - .drop-empty-rules { - @apply hover:font-bold; + @media (min-width: 640px) { + .apply-components { + max-width: 640px; + } } - .apply-group { - @apply group-hover:font-bold; + @media (min-width: 768px) { + .apply-components { + max-width: 768px; + } } - .apply-dark-mode { - @apply dark:font-bold; + @media (min-width: 1024px) { + .apply-components { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .apply-components { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .apply-components { + max-width: 1536px; + } + } + .apply-components { + margin-left: auto; + margin-right: auto; + } + .drop-empty-rules:hover, + .group:hover .apply-group, + :is(.dark .apply-dark-mode) { + font-weight: 700; } .apply-with-existing:hover { - @apply font-normal sm:bg-green-500; + font-weight: 400; + } + @media (min-width: 640px) { + .apply-with-existing:hover { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } } .multiple, .selectors { - @apply font-bold group-hover:font-normal; + font-weight: 700; } - .list { - @apply space-y-4; + .group:hover .multiple, + .group:hover .selectors { + font-weight: 400; } - .nested { - .example { - @apply font-bold hover:font-normal; - } + .list > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } - .apply-order-a { - @apply m-5 mt-6; + .nested .example { + font-weight: 700; } + .nested .example:hover { + font-weight: 400; + } + .apply-order-a, .apply-order-b { - @apply m-5 mt-6; + margin: 1.5rem 1.25rem 1.25rem; } - .apply-dark-group-example-a { - @apply dark:group-hover:bg-green-500; + :is(.dark .group:hover .apply-dark-group-example-a) { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } - .crazy-example { - @apply sm:motion-safe:group-active:focus:opacity-10; + @media (min-width: 640px) { + @media (prefers-reduced-motion: no-preference) { + .group:active .crazy-example:focus { + opacity: 0.1; + } + } } - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .theme-test { - color: #3b82f6; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, - Segoe UI Symbol, Noto Color Emoji; - } - @media (min-width: 1024px) { - .screen-test { - color: purple; - } - } - .apply-1, - .apply-2 { - margin-top: 1.5rem; - } - .apply-test { - --tw-bg-opacity: 1; - background-color: rgb(236 72 153 / var(--tw-bg-opacity)); - margin-top: 1.5rem; - } - .apply-test:hover, - .apply-test:hover:focus { - font-weight: 700; - } - @media (min-width: 640px) { - .apply-test { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - .apply-test:nth-child(2n):focus { - --tw-bg-opacity: 1; - background-color: rgb(251 207 232 / var(--tw-bg-opacity)); - } - } - .apply-components { - width: 100%; - } - @media (min-width: 640px) { - .apply-components { - max-width: 640px; - } - } - @media (min-width: 768px) { - .apply-components { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .apply-components { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .apply-components { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .apply-components { - max-width: 1536px; - } - } - .apply-components { - margin-left: auto; - margin-right: auto; - } - .drop-empty-rules:hover, - .group:hover .apply-group, - :is(.dark .apply-dark-mode) { - font-weight: 700; - } - .apply-with-existing:hover { - font-weight: 400; - } - @media (min-width: 640px) { - .apply-with-existing:hover { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - } - .multiple, - .selectors { - font-weight: 700; - } - .group:hover .multiple, - .group:hover .selectors { - font-weight: 400; - } - .list > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); - } - .nested .example { - font-weight: 700; - } - .nested .example:hover { - font-weight: 400; - } - .apply-order-a, - .apply-order-b { - margin: 1.5rem 1.25rem 1.25rem; - } - :is(.dark .group:hover .apply-dark-group-example-a) { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - @media (min-width: 640px) { - @media (prefers-reduced-motion: no-preference) { - .group:active .crazy-example:focus { - opacity: 0.1; - } - } - } - h1 { - font-size: 1.5rem; - font-weight: 700; - } - h1:first-child { - margin-top: 0; - } - div { - background: #654321; - } - ${defaults} + h1 { + font-size: 1.5rem; + font-weight: 700; + } + h1:first-child { + margin-top: 0; + } + div { + background: #654321; + } + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + .test-apply-font-variant { + --tw-ordinal: ordinal; + --tw-numeric-spacing: tabular-nums; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + } + .custom-component { + background: #123456; + } + *, + :before, + :after { + padding: 5px; + } + *, + :before, + :after { + padding: 5px; + } + ::-webkit-backdrop { + padding: 5px; + } + ::backdrop { + padding: 5px; + } + .foo .bg-black { + -webkit-appearance: none; + appearance: none; + } + .inset-6 { + inset: 1.5rem; + } + .inset-x-1 { + left: 0.25rem; + right: 0.25rem; + } + .end-8 { + inset-inline-end: 2rem; + } + .start-4 { + inset-inline-start: 1rem; + } + .mx-1 { + margin-left: 0.25rem; + margin-right: 0.25rem; + } + .me-8 { + margin-inline-end: 2rem; + } + .ms-4 { + margin-inline-start: 1rem; + } + .mt-6 { + margin-top: 1.5rem; + } + .line-clamp-2 { + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-\[33\] { + -webkit-line-clamp: 33; + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-\[var\(--line-clamp-variable\)\] { + -webkit-line-clamp: var(--line-clamp-variable); + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-none { + -webkit-line-clamp: none; + -webkit-box-orient: horizontal; + display: block; + overflow: visible; + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { + grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .rounded-e { + border-start-end-radius: 0.25rem; + border-end-end-radius: 0.25rem; + } + .rounded-s { + border-start-start-radius: 0.25rem; + border-end-start-radius: 0.25rem; + } + .rounded-es { + border-end-start-radius: 0.25rem; + } + .rounded-ss { + border-start-start-radius: 0.25rem; + } + .border-2 { + border-width: 2px; + } + .border-e-4 { + border-inline-end-width: 4px; + } + .border-s-0 { + border-inline-start-width: 0; + } + .border-black { + --tw-border-opacity: 1; + border-color: rgb(0 0 0 / var(--tw-border-opacity)); + } + .border-e-red-400 { + --tw-border-opacity: 1; + border-inline-end-color: rgb(248 113 113 / var(--tw-border-opacity)); + } + .border-s-green-500 { + --tw-border-opacity: 1; + border-inline-start-color: rgb(34 197 94 / var(--tw-border-opacity)); + } + .bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .bg-green-500 { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + .bg-hero--home-1 { + background-image: url('/images/homepage-1.jpg'); + } + .from-foo { + --tw-gradient-from: #bada55 var(--tw-gradient-from-position); + --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; + } + .pe-8 { + padding-inline-end: 2rem; + } + .ps-4 { + padding-inline-start: 1rem; + } + .pt-6 { + padding-top: 1.5rem; + } + .text-center { + text-align: center; + } + .font-medium { + font-weight: 500; + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), + 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .shadow-sm { + --tw-shadow: 0 1px 2px 0 #0000000d; + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .magic-none { + magic: none; + } + .magic-tons { + magic: tons; + } + .custom-util { + background: #abcdef; + } + *, + :before, + :after { + margin: 10px; + } + *, + :before, + :after { + margin: 10px; + } + ::-webkit-backdrop { + margin: 10px; + } + ::backdrop { + margin: 10px; + } + .hover\:container:hover { + width: 100%; + } + @media (min-width: 640px) { + .hover\:container:hover { + max-width: 640px; + } + } + @media (min-width: 768px) { + .hover\:container:hover { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .hover\:container:hover { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .hover\:container:hover { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .hover\:container:hover { + max-width: 1536px; + } + } + @media (min-width: 640px) { + .sm\:container { width: 100%; } @media (min-width: 640px) { - .container { + .sm\:container { max-width: 640px; } } @media (min-width: 768px) { - .container { + .sm\:container { max-width: 768px; } } @media (min-width: 1024px) { - .container { + .sm\:container { max-width: 1024px; } } @media (min-width: 1280px) { - .container { + .sm\:container { max-width: 1280px; } } @media (min-width: 1536px) { - .container { + .sm\:container { max-width: 1536px; } } - .test-apply-font-variant { - --tw-ordinal: ordinal; + } + @media (min-width: 768px) { + .md\:container { + width: 100%; + } + @media (min-width: 640px) { + .md\:container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .md\:container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .md\:container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .md\:container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .md\:container { + max-width: 1536px; + } + } + } + .first\:pt-0:first-child { + padding-top: 0; + } + .hover\:scale-75:hover { + --tw-scale-x: 0.75; + --tw-scale-y: 0.75; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .hover\:font-bold:hover { + font-weight: 700; + } + .hover\:shadow-lg:hover { + --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), + 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .hover\:custom-util:hover { + background: #abcdef; + } + .focus\:font-normal:focus { + font-weight: 400; + } + .focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); + } + .focus\:hover\:font-light:hover:focus { + font-weight: 300; + } + .disabled\:font-bold:disabled { + font-weight: 700; + } + .group:hover .group-hover\:opacity-100 { + opacity: 1; + } + .group:hover .group-hover\:custom-util { + background: #abcdef; + } + .group:active .group-active\:opacity-10 { + opacity: 0.1; + } + .foo\:custom-util, + .foo\:hover\:custom-util:hover { + background: #abcdef !important; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + .motion-safe\:custom-util { + background: #abcdef; + } + } + @media (prefers-reduced-motion: reduce) { + .motion-reduce\:transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + } + :is(.dark .dark\:custom-util) { + background: #abcdef; + } + @media (min-width: 640px) { + .sm\:text-center { + text-align: center; + } + .sm\:tabular-nums { --tw-numeric-spacing: tabular-nums; font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction); } - .custom-component { - background: #123456; + .sm\:custom-util { + background: #abcdef; } - *, - :before, - :after, - ::backdrop { - padding: 5px; + @media (prefers-reduced-motion: no-preference) { + .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { + opacity: 0.1; + } } - .foo .bg-black { - appearance: none; - } - .inset-6 { - inset: 1.5rem; - } - .inset-x-1 { - left: 0.25rem; - right: 0.25rem; - } - .end-8 { - inset-inline-end: 2rem; - } - .start-4 { - inset-inline-start: 1rem; - } - .mx-1 { - margin-left: 0.25rem; - margin-right: 0.25rem; - } - .me-8 { - margin-inline-end: 2rem; - } - .ms-4 { - margin-inline-start: 1rem; - } - .mt-6 { - margin-top: 1.5rem; - } - .line-clamp-2 { - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[33\] { - -webkit-line-clamp: 33; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[var\(--line-clamp-variable\)\] { - -webkit-line-clamp: var(--line-clamp-variable); - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-none { - -webkit-line-clamp: none; - -webkit-box-orient: horizontal; - display: block; - overflow: visible; - } - .scale-50 { - --tw-scale-x: 0.5; - --tw-scale-y: 0.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-e { - border-start-end-radius: 0.25rem; - border-end-end-radius: 0.25rem; - } - .rounded-s { - border-start-start-radius: 0.25rem; - border-end-start-radius: 0.25rem; - } - .rounded-es { - border-end-start-radius: 0.25rem; - } - .rounded-ss { - border-start-start-radius: 0.25rem; - } - .border-2 { - border-width: 2px; - } - .border-e-4 { - border-inline-end-width: 4px; - } - .border-s-0 { - border-inline-start-width: 0; - } - .border-black { - --tw-border-opacity: 1; - border-color: rgb(0 0 0 / var(--tw-border-opacity)); - } - .border-e-red-400 { - --tw-border-opacity: 1; - border-inline-end-color: rgb(248 113 113 / var(--tw-border-opacity)); - } - .border-s-green-500 { - --tw-border-opacity: 1; - border-inline-start-color: rgb(34 197 94 / var(--tw-border-opacity)); - } - .bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .bg-green-500 { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .bg-hero--home-1 { - background-image: url('/images/homepage-1.jpg'); - } - .from-foo { - --tw-gradient-from: #bada55 var(--tw-gradient-from-position); - --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - .pe-8 { - padding-inline-end: 2rem; - } - .ps-4 { - padding-inline-start: 1rem; - } - .pt-6 { - padding-top: 1.5rem; - } - .text-center { + } + @media (min-width: 768px) { + .md\:text-center { text-align: center; } - .font-medium { - font-weight: 500; + .md\:opacity-50 { + opacity: 0.5; } - .shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .shadow-sm { + .md\:shadow-sm { --tw-shadow: 0 1px 2px 0 #0000000d; --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } - .magic-none { - magic: none; + .md\:hover\:border-r-blue-500\/30:hover { + border-right-color: #3b82f64d; } - .magic-tons { - magic: tons; - } - .custom-util { - background: #abcdef; - } - *, - :before, - :after, - ::backdrop { - margin: 10px; - } - .hover\:container:hover { - width: 100%; - } - @media (min-width: 640px) { - .hover\:container:hover { - max-width: 640px; - } - } - @media (min-width: 768px) { - .hover\:container:hover { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .hover\:container:hover { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .hover\:container:hover { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .hover\:container:hover { - max-width: 1536px; - } - } - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - @media (min-width: 768px) { - .md\:container { - width: 100%; - } - @media (min-width: 640px) { - .md\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .md\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .md\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .md\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .md\:container { - max-width: 1536px; - } - } - } - .first\:pt-0:first-child { - padding-top: 0; - } - .hover\:scale-75:hover { - --tw-scale-x: 0.75; - --tw-scale-y: 0.75; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:font-bold:hover { - font-weight: 700; - } - .hover\:shadow-lg:hover { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:custom-util:hover { - background: #abcdef; - } - .focus\:font-normal:focus { - font-weight: 400; - } - .focus\:ring-2:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); - } - .focus\:hover\:font-light:hover:focus { - font-weight: 300; - } - .disabled\:font-bold:disabled { - font-weight: 700; - } - .group:hover .group-hover\:opacity-100 { - opacity: 1; - } - .group:hover .group-hover\:custom-util { - background: #abcdef; - } - .group:active .group-active\:opacity-10 { - opacity: 0.1; - } - .foo\:custom-util, - .foo\:hover\:custom-util:hover { - background: #abcdef !important; + .md\:hover\:opacity-20:hover { + opacity: 0.2; } @media (prefers-reduced-motion: no-preference) { - .motion-safe\:transition { + .md\:motion-safe\:hover\:transition:hover { transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, + backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } - .motion-safe\:custom-util { - background: #abcdef; + :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { + background: #abcdef !important; } } - @media (prefers-reduced-motion: reduce) { - .motion-reduce\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - } - :is(.dark .dark\:custom-util) { - background: #abcdef; - } @media (min-width: 640px) { - .sm\:text-center { + .md\:sm\:text-center { text-align: center; } - .sm\:tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .sm\:custom-util { - background: #abcdef; - } - @media (prefers-reduced-motion: no-preference) { - .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { - opacity: 0.1; - } - } } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:opacity-50 { - opacity: 0.5; - } - .md\:shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .md\:hover\:border-r-blue-500\/30:hover { - border-right-color: #3b82f64d; - } - .md\:hover\:opacity-20:hover { - opacity: 0.2; - } - @media (prefers-reduced-motion: no-preference) { - .md\:motion-safe\:hover\:transition:hover { - transition-property: color, background-color, border-color, text-decoration-color, - fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { - background: #abcdef !important; - } - } - @media (min-width: 640px) { - .md\:sm\:text-center { - text-align: center; - } - } + } + @media (min-width: 1280px) and (max-width: 1535px) { + .range\:text-right { + text-align: right; } - @media (min-width: 1280px) and (max-width: 1535px) { - .range\:text-right { - text-align: right; - } + } + @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { + .multi\:text-left { + text-align: left; } - @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { - .multi\:text-left { - text-align: left; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .theme-test { - color: #3b82f6; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, - Segoe UI Symbol, Noto Color Emoji; - } - @media (min-width: 1024px) { - .screen-test { - color: purple; - } - } - .apply-1, - .apply-2 { - margin-top: 1.5rem; - } - .apply-test { - background-color: #ec4899; - margin-top: 1.5rem; - } - .apply-test:hover, - .apply-test:hover:focus { - font-weight: 700; - } - @media (min-width: 640px) { - .apply-test { - background-color: #22c55e; - } - .apply-test:nth-child(2n):focus { - background-color: #fbcfe8; - } - } - .apply-components { - width: 100%; - } - @media (min-width: 640px) { - .apply-components { - max-width: 640px; - } - } - @media (min-width: 768px) { - .apply-components { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .apply-components { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .apply-components { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .apply-components { - max-width: 1536px; - } - } - .apply-components { - margin-left: auto; - margin-right: auto; - } - .drop-empty-rules:hover, - .group:hover .apply-group, - :is(.dark .apply-dark-mode) { - font-weight: 700; - } - .apply-with-existing:hover { - font-weight: 400; - } - @media (min-width: 640px) { - .apply-with-existing:hover { - background-color: #22c55e; - } - } - .multiple, - .selectors { - font-weight: 700; - } - .group:hover .multiple, - .group:hover .selectors { - font-weight: 400; - } - .list > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); - } - .nested .example { - font-weight: 700; - } - .nested .example:hover { - font-weight: 400; - } - .apply-order-a, - .apply-order-b { - margin: 1.5rem 1.25rem 1.25rem; - } - :is(.dark .group:hover .apply-dark-group-example-a) { - background-color: #22c55e; - } - @media (min-width: 640px) { - @media (prefers-reduced-motion: no-preference) { - .group:active .crazy-example:focus { - opacity: 0.1; - } - } - } - h1 { - font-size: 1.5rem; - font-weight: 700; - } - h1:first-child { - margin-top: 0; - } - div { - background: #654321; - } - ${defaults} - .container { - width: 100%; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .test-apply-font-variant { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .custom-component { - background: #123456; - } - *, - :before, - :after, - ::backdrop { - padding: 5px; - } - .foo .bg-black { - appearance: none; - } - .inset-6 { - inset: 1.5rem; - } - .inset-x-1 { - left: 0.25rem; - right: 0.25rem; - } - .end-8 { - inset-inline-end: 2rem; - } - .start-4 { - inset-inline-start: 1rem; - } - .mx-1 { - margin-left: 0.25rem; - margin-right: 0.25rem; - } - .me-8 { - margin-inline-end: 2rem; - } - .ms-4 { - margin-inline-start: 1rem; - } - .mt-6 { - margin-top: 1.5rem; - } - .line-clamp-2 { - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[33\] { - -webkit-line-clamp: 33; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[var\(--line-clamp-variable\)\] { - -webkit-line-clamp: var(--line-clamp-variable); - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-none { - -webkit-line-clamp: none; - -webkit-box-orient: horizontal; - display: block; - overflow: visible; - } - .scale-50 { - --tw-scale-x: 0.5; - --tw-scale-y: 0.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-e { - border-start-end-radius: 0.25rem; - border-end-end-radius: 0.25rem; - } - .rounded-s { - border-start-start-radius: 0.25rem; - border-end-start-radius: 0.25rem; - } - .rounded-es { - border-end-start-radius: 0.25rem; - } - .rounded-ss { - border-start-start-radius: 0.25rem; - } - .border-2 { - border-width: 2px; - } - .border-e-4 { - border-inline-end-width: 4px; - } - .border-s-0 { - border-inline-start-width: 0; - } - .border-black { - border-color: #000; - } - .border-e-red-400 { - border-inline-end-color: #f87171; - } - .border-s-green-500 { - border-inline-start-color: #22c55e; - } - .bg-black { - background-color: #000; - } - .bg-green-500 { - background-color: #22c55e; - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .bg-hero--home-1 { - background-image: url('/images/homepage-1.jpg'); - } - .from-foo { - --tw-gradient-from: #bada55 var(--tw-gradient-from-position); - --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - .pe-8 { - padding-inline-end: 2rem; - } - .ps-4 { - padding-inline-start: 1rem; - } - .pt-6 { - padding-top: 1.5rem; - } - .text-center { - text-align: center; - } - .font-medium { - font-weight: 500; - } - .shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .magic-none { - magic: none; - } - .magic-tons { - magic: tons; - } - .custom-util { - background: #abcdef; - } - *, - :before, - :after, - ::backdrop { - margin: 10px; - } - .hover\:container:hover { - width: 100%; - } - @media (min-width: 640px) { - .hover\:container:hover { - max-width: 640px; - } - } - @media (min-width: 768px) { - .hover\:container:hover { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .hover\:container:hover { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .hover\:container:hover { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .hover\:container:hover { - max-width: 1536px; - } - } - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - @media (min-width: 768px) { - .md\:container { - width: 100%; - } - @media (min-width: 640px) { - .md\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .md\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .md\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .md\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .md\:container { - max-width: 1536px; - } - } - } - .first\:pt-0:first-child { - padding-top: 0; - } - .hover\:scale-75:hover { - --tw-scale-x: 0.75; - --tw-scale-y: 0.75; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:font-bold:hover { - font-weight: 700; - } - .hover\:shadow-lg:hover { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:custom-util:hover { - background: #abcdef; - } - .focus\:font-normal:focus { - font-weight: 400; - } - .focus\:ring-2:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .focus\:ring-blue-500:focus { - --tw-ring-color: #3b82f6; - } - .focus\:hover\:font-light:hover:focus { - font-weight: 300; - } - .disabled\:font-bold:disabled { - font-weight: 700; - } - .group:hover .group-hover\:opacity-100 { - opacity: 1; - } - .group:hover .group-hover\:custom-util { - background: #abcdef; - } - .group:active .group-active\:opacity-10 { - opacity: 0.1; - } - .foo\:custom-util, - .foo\:hover\:custom-util:hover { - background: #abcdef !important; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .motion-safe\:custom-util { - background: #abcdef; - } - } - @media (prefers-reduced-motion: reduce) { - .motion-reduce\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - } - :is(.dark .dark\:custom-util) { - background: #abcdef; - } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .sm\:custom-util { - background: #abcdef; - } - @media (prefers-reduced-motion: no-preference) { - .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { - opacity: 0.1; - } - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:opacity-50 { - opacity: 0.5; - } - .md\:shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .md\:hover\:border-r-blue-500\/30:hover { - border-right-color: #3b82f64d; - } - .md\:hover\:opacity-20:hover { - opacity: 0.2; - } - @media (prefers-reduced-motion: no-preference) { - .md\:motion-safe\:hover\:transition:hover { - transition-property: color, background-color, border-color, text-decoration-color, - fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { - background: #abcdef !important; - } - } - @media (min-width: 640px) { - .md\:sm\:text-center { - text-align: center; - } - } - } - @media (min-width: 1280px) and (max-width: 1535px) { - .range\:text-right { - text-align: right; - } - } - @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { - .multi\:text-left { - text-align: left; - } - } - `) - }) + } + `) }) }) diff --git a/tests/layer-at-rules.test.js b/tests/layer-at-rules.test.js index db98bbeb5..ac1b11bd5 100644 --- a/tests/layer-at-rules.test.js +++ b/tests/layer-at-rules.test.js @@ -1,321 +1,319 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('custom user-land utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('custom user-land utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @layer utilities { + .align-banana { + text-align: banana; + } } - let input = css` - @layer utilities { - .align-banana { - text-align: banana; - } + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer utilities { + .align-chocolate { + text-align: chocolate; } + } + ` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer utilities { - .align-chocolate { - text-align: chocolate; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .uppercase { + text-transform: uppercase; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .uppercase { - text-transform: uppercase; - } - .align-banana, - .hover\:align-banana:hover { - text-align: banana; - } - .focus\:hover\:align-chocolate:hover:focus { - text-align: chocolate; - } - `) - }) + .align-banana, + .hover\:align-banana:hover { + text-align: banana; + } + .focus\:hover\:align-chocolate:hover:focus { + text-align: chocolate; + } + `) }) +}) - test('comments can be used inside layers without crashing', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('comments can be used inside layers without crashing', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer base { + /* Important base */ + div { + background-color: #bada55; + } } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer base { - /* Important base */ - div { - background-color: #bada55; - } + @layer utilities { + /* Important utility */ + .important-utility { + text-align: banana; } + } - @layer utilities { - /* Important utility */ + @layer components { + /* Important component */ + .important-component { + text-align: banana; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div { + background-color: #bada55; + } + ${defaults} + .important-component, .important-utility { - text-align: banana; - } + text-align: banana; } - - @layer components { - /* Important component */ - .important-component { - text-align: banana; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div { - background-color: #bada55; - } - ${defaults} - .important-component, - .important-utility { - text-align: banana; - } - `) - }) + `) }) +}) - test('comments can be used inside layers (with important) without crashing', () => { - let config = { - important: true, - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('comments can be used inside layers (with important) without crashing', () => { + let config = { + important: true, + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer base { + /* Important base */ + div { + background-color: #bada55; + } } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer base { - /* Important base */ - div { - background-color: #bada55; - } + @layer utilities { + /* Important utility */ + .important-utility { + text-align: banana; } + } - @layer utilities { - /* Important utility */ - .important-utility { - text-align: banana; - } + @layer components { + /* Important component */ + .important-component { + text-align: banana; } + } + ` - @layer components { - /* Important component */ - .important-component { - text-align: banana; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div { + background-color: #bada55; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div { - background-color: #bada55; - } - ${defaults} - .important-component { - text-align: banana; - } - .important-utility { - text-align: banana !important; - } - `) - }) + ${defaults} + .important-component { + text-align: banana; + } + .important-utility { + text-align: banana !important; + } + `) }) +}) - test('layers are grouped and inserted at the matching @tailwind rule', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addBase, addComponents, addUtilities }) { - addBase({ body: { margin: 0 } }) +test('layers are grouped and inserted at the matching @tailwind rule', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addBase, addComponents, addUtilities }) { + addBase({ body: { margin: 0 } }) - addComponents({ - '.input': { background: 'white' }, - }) + addComponents({ + '.input': { background: 'white' }, + }) - addUtilities({ - '.float-squirrel': { float: 'squirrel' }, - }) - }, - ], - corePlugins: { preflight: false }, + addUtilities({ + '.float-squirrel': { float: 'squirrel' }, + }) + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @layer vanilla { + strong { + font-weight: medium; + } } - let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer components { + .btn { + background: blue; + } + } + + @layer utilities { + .align-banana { + text-align: banana; + } + } + + @layer base { + h1 { + font-weight: bold; + } + } + + @layer components { + .card { + border-radius: 12px; + } + } + + @layer base { + p { + font-weight: normal; + } + } + + @layer utilities { + .align-sandwich { + text-align: sandwich; + } + } + + @layer chocolate { + a { + text-decoration: underline; + } + } + ` + + expect.assertions(2) + + return run(input, config).then((result) => { + expect(result.warnings().length).toBe(0) + expect(result.css).toMatchFormattedCss(css` @layer vanilla { strong { font-weight: medium; } } - - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer components { - .btn { - background: blue; - } + body { + margin: 0; } - - @layer utilities { - .align-banana { - text-align: banana; - } + h1 { + font-weight: bold; } - - @layer base { - h1 { - font-weight: bold; - } + p { + font-weight: normal; } - - @layer components { - .card { - border-radius: 12px; - } + ${defaults} + .input { + background: #fff; } - - @layer base { - p { - font-weight: normal; - } + .btn { + background: #00f; } - - @layer utilities { - .align-sandwich { - text-align: sandwich; - } + .card { + border-radius: 12px; + } + .float-squirrel { + float: squirrel; + } + .align-banana { + text-align: banana; + } + .align-sandwich { + text-align: sandwich; } - @layer chocolate { a { text-decoration: underline; } } - ` - - expect.assertions(2) - - return run(input, config).then((result) => { - expect(result.warnings().length).toBe(0) - expect(result.css).toMatchFormattedCss(css` - @layer vanilla { - strong { - font-weight: medium; - } - } - body { - margin: 0; - } - h1 { - font-weight: bold; - } - p { - font-weight: normal; - } - ${defaults} - .input { - background: #fff; - } - .btn { - background: #00f; - } - .card { - border-radius: 12px; - } - .float-squirrel { - float: squirrel; - } - .align-banana { - text-align: banana; - } - .align-sandwich { - text-align: sandwich; - } - @layer chocolate { - a { - text-decoration: underline; - } - } - `) - }) - }) - - it('should keep `@supports` rules inside `@layer`s', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .test { - --tw-test: 1; - } - - @supports (backdrop-filter: blur(1px)) { - .test { - --tw-test: 0.9; - } - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .test { - --tw-test: 1; - } - @supports (backdrop-filter: blur(1px)) { - .test { - --tw-test: 0.9; - } - } - `) - }) + `) + }) +}) + +it('should keep `@supports` rules inside `@layer`s', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .test { + --tw-test: 1; + } + + @supports (backdrop-filter: blur(1px)) { + .test { + --tw-test: 0.9; + } + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .test { + --tw-test: 1; + } + @supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { + .test { + --tw-test: 0.9; + } + } + `) }) }) diff --git a/tests/layer-without-tailwind.test.js b/tests/layer-without-tailwind.test.js index f15d43351..4122873c9 100644 --- a/tests/layer-without-tailwind.test.js +++ b/tests/layer-without-tailwind.test.js @@ -1,81 +1,79 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('using @layer without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], - } +test('using @layer without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` - @layer components { - .foo { - color: black; - } + let input = css` + @layer components { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@layer components` is used but no matching `@tailwind components` directive is present.' - ) - }) - - test('using @responsive without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` - @responsive { - .foo { - color: black; - } + await expect(run(input, config)).rejects.toThrowError( + '`@layer components` is used but no matching `@tailwind components` directive is present.' + ) +}) + +test('using @responsive without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @responsive { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@responsive` is used but `@tailwind utilities` is missing.' - ) - }) - - test('using @variants without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` - @variants hover { - .foo { - color: black; - } + await expect(run(input, config)).rejects.toThrowError( + '`@responsive` is used but `@tailwind utilities` is missing.' + ) +}) + +test('using @variants without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @variants hover { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@variants` is used but `@tailwind utilities` is missing.' - ) - }) - - test('non-Tailwind @layer rules are okay', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` + await expect(run(input, config)).rejects.toThrowError( + '`@variants` is used but `@tailwind utilities` is missing.' + ) +}) + +test('non-Tailwind @layer rules are okay', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @layer custom { + .foo { + color: black; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` @layer custom { .foo { - color: black; + color: #000; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @layer custom { - .foo { - color: #000; - } - } - `) - }) + `) }) }) diff --git a/tests/match-components.test.js b/tests/match-components.test.js index a8b546127..8f6241724 100644 --- a/tests/match-components.test.js +++ b/tests/match-components.test.js @@ -1,86 +1,82 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to matchComponents', () => { - let config = { - content: [ - { - raw: html`
-
-
- -
`, - }, - ], - corePlugins: { - preflight: false, +it('should be possible to matchComponents', () => { + let config = { + content: [ + { + raw: html`
+
+
+ +
`, }, - plugins: [ - function ({ matchComponents }) { - matchComponents({ - card: (value) => { - return [ - { color: value }, - { - '.card-header': { - borderTopWidth: 3, - borderTopColor: value, - }, + ], + corePlugins: { + preflight: false, + }, + plugins: [ + function ({ matchComponents }) { + matchComponents({ + card: (value) => { + return [ + { color: value }, + { + '.card-header': { + borderTopWidth: 3, + borderTopColor: value, }, - { - '.card-footer': { - borderBottomWidth: 3, - borderBottomColor: value, - }, + }, + { + '.card-footer': { + borderBottomWidth: 3, + borderBottomColor: value, }, - ] - }, - }) - }, - ], - } + }, + ] + }, + }) + }, + ], + } - return run('@tailwind base; @tailwind components; @tailwind utilities', config).then( - (result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .card-\[\#0088cc\] { - color: #08c; - } - .card-\[\#0088cc\] .card-header { - border-top-width: 3px; - border-top-color: #08c; - } - .card-\[\#0088cc\] .card-footer { - border-bottom-width: 3px; - border-bottom-color: #08c; - } - .text-center { - text-align: center; - } - .font-bold { - font-weight: 700; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:card-\[\#f0f\]:hover { - color: #f0f; - } - .hover\:card-\[\#f0f\]:hover .card-header { - border-top-width: 3px; - border-top-color: #f0f; - } - .hover\:card-\[\#f0f\]:hover .card-footer { - border-bottom-width: 3px; - border-bottom-color: #f0f; - } - `) + return run('@tailwind base; @tailwind components; @tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .card-\[\#0088cc\] { + color: #08c; } - ) + .card-\[\#0088cc\] .card-header { + border-top-width: 3px; + border-top-color: #08c; + } + .card-\[\#0088cc\] .card-footer { + border-bottom-width: 3px; + border-bottom-color: #08c; + } + .text-center { + text-align: center; + } + .font-bold { + font-weight: 700; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .hover\:card-\[\#f0f\]:hover { + color: #f0f; + } + .hover\:card-\[\#f0f\]:hover .card-header { + border-top-width: 3px; + border-top-color: #f0f; + } + .hover\:card-\[\#f0f\]:hover .card-footer { + border-bottom-width: 3px; + border-bottom-color: #f0f; + } + `) }) }) diff --git a/tests/match-utilities.test.js b/tests/match-utilities.test.js index 9b3cd4c56..a9705b021 100644 --- a/tests/match-utilities.test.js +++ b/tests/match-utilities.test.js @@ -1,575 +1,573 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('match utilities with modifiers', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, +test('match utilities with modifiers', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => ({ - color: `${value}_${modifier}`, - }), + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => ({ + color: `${value}_${modifier}`, + }), + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + '2': 'two', + '1/foo': 'onefoo', + '[8]/[9]': 'eightnine', }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - '2': 'two', - '1/foo': 'onefoo', - '[8]/[9]': 'eightnine', - }, - modifiers: 'any', - } - ) - }, - ], + modifiers: 'any', + } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; } + .test-1\/\[foo\] { + color: one_[foo]; + } + .test-1\/foo { + color: onefoo_null; + } + .test-2\/foo { + color: two_foo; + } + .test-\[8\]\/\[9\] { + color: eightnine_null; + } + .test\/\[foo\] { + color: default_[foo]; + } + .test\/foo { + color: default_foo; + } + `) +}) - let input = css` - @tailwind utilities; - ` +test('match utilities with modifiers in the config', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, - let result = await run(input, config) + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => ({ + color: `${value}_${modifier}`, + }), + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + }, + modifiers: { + foo: 'mewtwo', + }, + } + ) + }, + ], + } + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; + } + .test-1\/\[bar\] { + color: one_bar; + } + .test-1\/foo { + color: one_mewtwo; + } + .test\/\[bar\] { + color: default_bar; + } + .test\/foo { + color: default_mewtwo; + } + `) +}) + +test('match utilities can omit utilities by returning null', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => + modifier === 'bad' + ? null + : { + color: `${value}_${modifier}`, + }, + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + }, + modifiers: 'any', + } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; + } + .test\/good { + color: default_good; + } + `) +}) + +test('matching utilities with a basic configured value', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value) => ({ value }), + }, + { + values: { + foo: 'value_foo', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test-1\/\[foo\] { - color: one_[foo]; - } - .test-1\/foo { - color: onefoo_null; - } - .test-2\/foo { - color: two_foo; - } - .test-\[8\]\/\[9\] { - color: eightnine_null; - } - .test\/\[foo\] { - color: default_[foo]; - } - .test\/foo { - color: default_foo; + .test-foo { + value: value_foo; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: { + bar: 'configured_bar', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/bar { + value: foo; + modifier: configured_bar; + } + `) + }) +}) + +test('matching utilities with an configured value and an arbitrary modifier (raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: 'any', // Raw `[value]` + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-foo\/\[bar\] { + value: configured_foo; + modifier: [bar]; + } + `) + }) +}) + +test('matching utilities with an configured value and an arbitrary modifier (non-raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-foo\/\[bar\] { + value: configured_foo; + modifier: bar; + } + `) + }) +}) + +test('matching utilities with an configured value and a configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: { + bar: 'configured_bar', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-foo\/bar { + value: configured_foo; + modifier: configured_bar; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and an arbitrary modifier (raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: 'any', + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/\[bar\] { + value: foo; + modifier: [bar]; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and an arbitrary modifier (non-raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/\[bar\] { + value: foo; + modifier: bar; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = any)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + modifiers: 'any', + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = {})', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and a configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/bar': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[foo\]\/bar { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like a configured value and an arbitrary modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + 'foo/[bar]': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-foo\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that does not match the configured type', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'not-a-percentage', + }, + type: ['percentage'], + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-foo { + value: not-a-percentage; } `) }) - - test('match utilities with modifiers in the config', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => ({ - color: `${value}_${modifier}`, - }), - }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - }, - modifiers: { - foo: 'mewtwo', - }, - } - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test-1\/\[bar\] { - color: one_bar; - } - .test-1\/foo { - color: one_mewtwo; - } - .test\/\[bar\] { - color: default_bar; - } - .test\/foo { - color: default_mewtwo; - } - `) - }) - - test('match utilities can omit utilities by returning null', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => - modifier === 'bad' - ? null - : { - color: `${value}_${modifier}`, - }, - }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - }, - modifiers: 'any', - } - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test\/good { - color: default_good; - } - `) - }) - - test('matching utilities with a basic configured value', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value) => ({ value }), - }, - { - values: { - foo: 'value_foo', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo { - value: value_foo; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: { - bar: 'configured_bar', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/bar { - value: foo; - modifier: configured_bar; - } - `) - }) - }) - - test('matching utilities with an configured value and an arbitrary modifier (raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: 'any', // Raw `[value]` - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: configured_foo; - modifier: [bar]; - } - `) - }) - }) - - test('matching utilities with an configured value and an arbitrary modifier (non-raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: configured_foo; - modifier: bar; - } - `) - }) - }) - - test('matching utilities with an configured value and a configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: { - bar: 'configured_bar', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/bar { - value: configured_foo; - modifier: configured_bar; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and an arbitrary modifier (raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: 'any', - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: foo; - modifier: [bar]; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and an arbitrary modifier (non-raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: foo; - modifier: bar; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = any)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - modifiers: 'any', - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = {})', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and a configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/bar': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/bar { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like a configured value and an arbitrary modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - 'foo/[bar]': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that does not match the configured type', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'not-a-percentage', - }, - type: ['percentage'], - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo { - value: not-a-percentage; - } - `) - }) - }) }) diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index e4330f7a9..2923b10c0 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -1,856 +1,820 @@ import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('partial arbitrary variants', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `.potato-${flavor} &`) - }, - ], - } +test('partial arbitrary variants', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `.potato-${flavor} &`) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .potato-baked .potato-\[baked\]\:w-3 { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .potato-baked .potato-\[baked\]\:w-3 { + width: 0.75rem; + } + .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); + } + `) + }) +}) + +test('partial arbitrary variants with at-rules', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `@media (potato: ${flavor})`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3 { width: 0.75rem; } - .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200 { --tw-bg-opacity: 1; background-color: rgb(254 240 138 / var(--tw-bg-opacity)); } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .potato-baked .potato-\[baked\]\:w-3 { + } + `) + }) +}) + +test('partial arbitrary variants with at-rules and placeholder', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `@media (potato: ${flavor}) { &:potato }`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3:potato { width: 0.75rem; } - .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { - background-color: #fef08a; + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200:potato { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); } - `) - }) + } + `) }) +}) - test('partial arbitrary variants with at-rules', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `@media (potato: ${flavor})`) - }, - ], - } +test('partial arbitrary variants with default values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('tooltip', (side) => `&${side}`, { + values: { + bottom: '[data-location="bottom"]', + top: '[data-location="top"]', + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3 { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 240 138 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3 { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200 { - background-color: #fef08a; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tooltip-bottom\:mt-2[data-location='bottom'] { + margin-top: 0.5rem; + } + .tooltip-top\:mb-2[data-location='top'] { + margin-bottom: 0.5rem; + } + `) }) +}) - test('partial arbitrary variants with at-rules and placeholder', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `@media (potato: ${flavor}) { &:potato }`) - }, - ], - } +test('matched variant values maintain the sort order they are registered in', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('alphabet', (side) => `&${side}`, { + values: { + a: '[data-value="a"]', + b: '[data-value="b"]', + c: '[data-value="c"]', + d: '[data-value="d"]', + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3:potato { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200:potato { - --tw-bg-opacity: 1; - background-color: rgb(254 240 138 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3:potato { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200:potato { - background-color: #fef08a; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .alphabet-a\:underline[data-value='a'], + .alphabet-b\:underline[data-value='b'], + .alphabet-c\:underline[data-value='c'], + .alphabet-d\:underline[data-value='d'] { + text-decoration-line: underline; + } + `) }) +}) - test('partial arbitrary variants with default values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('tooltip', (side) => `&${side}`, { - values: { - bottom: '[data-location="bottom"]', - top: '[data-location="top"]', - }, - }) - }, - ], - } +test('matchVariant can return an array of format strings from the function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('test', (selector) => + selector.split(',').map((selector) => `&.${selector} > *`) + ) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tooltip-bottom\:mt-2[data-location='bottom'] { - margin-top: 0.5rem; - } - .tooltip-top\:mb-2[data-location='top'] { - margin-bottom: 0.5rem; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[a\,b\,c\]\:underline.a > *, + .test-\[a\,b\,c\]\:underline.b > *, + .test-\[a\,b\,c\]\:underline.c > * { + text-decoration-line: underline; + } + `) }) +}) - test('matched variant values maintain the sort order they are registered in', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('alphabet', (side) => `&${side}`, { - values: { - a: '[data-value="a"]', - b: '[data-value="b"]', - c: '[data-value="c"]', - d: '[data-value="d"]', - }, - }) - }, - ], - } +it('should be possible to sort variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .alphabet-a\:underline[data-value='a'], - .alphabet-b\:underline[data-value='b'], - .alphabet-c\:underline[data-value='c'], - .alphabet-d\:underline[data-value='d'] { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { + .testmin-\[500px\]\:underline { text-decoration-line: underline; } - `) - }) - }) - - test('matchVariant can return an array of format strings from the function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('test', (selector) => - selector.split(',').map((selector) => `&.${selector} > *`) - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test-\[a\,b\,c\]\:underline.a > *, - .test-\[a\,b\,c\]\:underline.b > *, - .test-\[a\,b\,c\]\:underline.c > * { - text-decoration-line: underline; + } + @media (min-width: 700px) { + .testmin-\[700px\]\:italic { + font-style: italic; } - `) - }) + } + `) }) +}) - it('should be possible to sort variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - }, - ], - } +it('should be possible to compare arbitrary variants and hardcoded variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + values: { + example: '600px', + }, + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .testmin-\[500px\]\:underline { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { + .testmin-\[500px\]\:italic { + font-style: italic; + } + } + @media (min-width: 600px) { + .testmin-example\:italic { + font-style: italic; + } + } + @media (min-width: 700px) { + .testmin-\[700px\]\:italic { + font-style: italic; + } + } + `) + }) +}) + +it('should be possible to sort stacked arbitrary variants correctly', () => { + let config = { + content: [ + { + raw: html` +
+ +
+ +
+ +
+ +
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (min-width: 700px) { - .testmin-\[700px\]\:italic { - font-style: italic; + @media (max-width: 350px) { + .testmin-\[100px\]\:testmax-\[350px\]\:underline { + text-decoration-line: underline; } } - `) - }) + @media (max-width: 300px) { + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + @media (min-width: 150px) { + @media (max-width: 400px) { + .testmin-\[150px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + } + `) }) +}) - it('should be possible to compare arbitrary variants and hardcoded variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - values: { - example: '600px', - }, - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - }, - ], - } +it('should maintain sort from other variants, if sort functions of arbitrary variants return 0', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) - let input = css` - @tailwind utilities; - ` + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .testmin-\[500px\]\:italic { - font-style: italic; + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 200px) { + .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, + .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { + text-decoration-line: underline; } } - @media (min-width: 600px) { - .testmin-example\:italic { - font-style: italic; - } - } - @media (min-width: 700px) { - .testmin-\[700px\]\:italic { - font-style: italic; - } - } - `) - }) + } + `) }) +}) - it('should be possible to sort stacked arbitrary variants correctly', () => { - let config = { - content: [ - { - raw: html` -
- -
- -
- -
- -
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) +it('should sort arbitrary variants left to right (1)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } + let input = css` + @tailwind utilities; + ` - let input = css` - @tailwind utilities; - ` + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + @media (max-width: 300px) { + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + @media (min-width: 200px) { + @media (max-width: 400px) { + .testmin-\[200px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + @media (max-width: 300px) { + .testmin-\[200px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + `) + }) +}) - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` +it('should sort arbitrary variants left to right (2)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (max-width: 400px) { @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 350px) { - .testmin-\[100px\]\:testmax-\[350px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } - } - } - @media (min-width: 150px) { - @media (max-width: 400px) { - .testmin-\[150px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - it('should maintain sort from other variants, if sort functions of arbitrary variants return 0', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 200px) { - .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, - .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - it('should sort arbitrary variants left to right (1)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + .testmax-\[400px\]\:testmin-\[100px\]\:underline { + text-decoration-line: underline; } } @media (min-width: 200px) { - @media (max-width: 400px) { - .testmin-\[200px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[200px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + .testmax-\[400px\]\:testmin-\[200px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) + } - it('should sort arbitrary variants left to right (2)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (max-width: 400px) { - @media (min-width: 100px) { - .testmax-\[400px\]\:testmin-\[100px\]\:underline { - text-decoration-line: underline; - } + @media (max-width: 300px) { + @media (min-width: 100px) { + .testmax-\[300px\]\:testmin-\[100px\]\:underline { + text-decoration-line: underline; } - @media (min-width: 200px) { - .testmax-\[400px\]\:testmin-\[200px\]\:underline { - text-decoration-line: underline; + } + @media (min-width: 200px) { + .testmax-\[300px\]\:testmin-\[200px\]\:underline { + text-decoration-line: underline; + } + } + } + `) + }) +}) + +it('should guarantee that we are not passing values from other variants to the wrong function', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + let lookup = ['100px', '200px'] + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { + throw new Error('We are seeing values that should not be there!') } + return lookup.indexOf(a.value) - lookup.indexOf(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + let lookup = ['300px', '400px'] + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { + throw new Error('We are seeing values that should not be there!') + } + return lookup.indexOf(z.value) - lookup.indexOf(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; } } @media (max-width: 300px) { - @media (min-width: 100px) { - .testmax-\[300px\]\:testmin-\[100px\]\:underline { - text-decoration-line: underline; - } - } - @media (min-width: 200px) { - .testmax-\[300px\]\:testmin-\[200px\]\:underline { - text-decoration-line: underline; - } + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) + } - it('should guarantee that we are not passing values from other variants to the wrong function', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - let lookup = ['100px', '200px'] - if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { - throw new Error('We are seeing values that should not be there!') - } - return lookup.indexOf(a.value) - lookup.indexOf(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - let lookup = ['300px', '400px'] - if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { - throw new Error('We are seeing values that should not be there!') - } - return lookup.indexOf(z.value) - lookup.indexOf(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + @media (min-width: 200px) { + @media (max-width: 400px) { + .testmin-\[200px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; } } - @media (min-width: 200px) { - @media (max-width: 400px) { - .testmin-\[200px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - - @media (max-width: 300px) { - .testmin-\[200px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + @media (max-width: 300px) { + .testmin-\[200px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) - - it('should default to the DEFAULT value for variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value} &`, { - values: { - DEFAULT: '.bar', - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo.bar .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should not generate anything if the matchVariant does not have a DEFAULT value configured', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value} &`) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) - }) - - it('should be possible to use `null` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === null ? '-good' : '-bad'} &`, { - values: { DEFAULT: null }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to use `undefined` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { - values: { DEFAULT: undefined }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to use `undefined` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { - values: { DEFAULT: undefined }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should not break things', () => { - let config = {} - - let context = createContext(resolveConfig(config)) - let [[, fn]] = context.variantMap.get('group') - - let format - - expect( - fn({ - format(input) { - format = input - }, - }) - ).toBe(undefined) - - expect(format).toBe(':merge(.group) &') + } + `) }) }) + +it('should default to the DEFAULT value for variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value} &`, { + values: { + DEFAULT: '.bar', + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo.bar .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should not generate anything if the matchVariant does not have a DEFAULT value configured', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value} &`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) + }) +}) + +it('should be possible to use `null` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === null ? '-good' : '-bad'} &`, { + values: { DEFAULT: null }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to use `undefined` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { + values: { DEFAULT: undefined }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to use `undefined` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { + values: { DEFAULT: undefined }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should not break things', () => { + let config = {} + + let context = createContext(resolveConfig(config)) + let [[, fn]] = context.variantMap.get('group') + + let format + + expect( + fn({ + format(input) { + format = input + }, + }) + ).toBe(undefined) + + expect(format).toBe(':merge(.group) &') +}) diff --git a/tests/min-max-screen-variants.test.js b/tests/min-max-screen-variants.test.js index a86c6f6cd..beab47ac0 100644 --- a/tests/min-max-screen-variants.test.js +++ b/tests/min-max-screen-variants.test.js @@ -1,656 +1,642 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - let defaultScreens = { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', +let defaultScreens = { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', +} + +it('sorts min and max correctly relative to screens and each other', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, } - it('sorts min and max correctly relative to screens and each other', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (max-width: 800px) { - .max-\[800px\]\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 800px) { - .min-\[800px\]\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('works when using min variants screens config is empty and variants all use the same unit', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } + @media (max-width: 800px) { + .max-\[800px\]\:font-bold { + font-weight: 700; + } + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } @media (min-width: 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } } `) - - expect().not.toHaveBeenWarned() }) +}) - it('works when using max variants screens config is empty and variants all use the same unit', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, +it('works when using min variants screens config is empty and variants all use the same unit', async () => { + let config = { + content: [ + { + raw: html` +
+ `, }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 800px) { + .min-\[800px\]\:font-bold { + font-weight: 700; + } + } + `) - let input = css` - @tailwind utilities; - ` + expect().not.toHaveBeenWarned() +}) - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (max-width: 800px) { - .max-\[800px\]\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('converts simple min-width screens for max variant', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, +it('works when using max variants screens config is empty and variants all use the same unit', () => { + let config = { + content: [ + { + raw: html` +
+ `, }, - } + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media not all and (min-width: 1024px) { - .max-lg\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media not all and (min-width: 640px) { - .max-sm\:font-bold { - font-weight: 700; - } - } - @media (max-width: 300px) { - .max-\[300px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('does not have keyed screens for min variant', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 300px) { - .min-\[300px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('warns when using min variants with complex screen configs', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - - // Any presence of an object makes it complex - yodawg: { min: '700px' }, - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } - @media (min-width: 640px) { - .sm\:font-bold { + @media (max-width: 800px) { + .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['complex-screen-config']) - }) - - it('warns when using min variants with simple configs containing mixed units', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '48rem', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 48rem) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['mixed-screen-units']) - }) - - it('warns when using min variants with mixed units (with screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using min variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using max variants with complex screen configs', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - - // Any presence of an object makes it complex - yodawg: { min: '700px' }, - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['complex-screen-config']) - }) - - it('warns when using max variants with simple configs containing mixed units', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '48rem', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 48rem) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['mixed-screen-units']) - }) - - it('warns when using max variants with mixed units (with screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using max variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) }) +}) - it('warns when using min and max variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, +it('converts simple min-width screens for max variant', () => { + let config = { + content: [ + { + raw: html` +
+ `, }, - } + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, + } - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } - @media (max-width: 700rem) { - .max-\[700rem\]\:font-bold { + @media not all and (min-width: 1024px) { + .max-lg\:font-bold { + font-weight: 700; + } + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media not all and (min-width: 640px) { + .max-sm\:font-bold { + font-weight: 700; + } + } + @media (max-width: 300px) { + .max-\[300px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { font-weight: 700; } } `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) }) }) + +it('does not have keyed screens for min variant', () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 300px) { + .min-\[300px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('warns when using min variants with complex screen configs', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + + // Any presence of an object makes it complex + yodawg: { min: '700px' }, + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['complex-screen-config']) +}) + +it('warns when using min variants with simple configs containing mixed units', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '48rem', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 48rem) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['mixed-screen-units']) +}) + +it('warns when using min variants with mixed units (with screens config)', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using min variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using max variants with complex screen configs', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + + // Any presence of an object makes it complex + yodawg: { min: '700px' }, + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['complex-screen-config']) +}) + +it('warns when using max variants with simple configs containing mixed units', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '48rem', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 48rem) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['mixed-screen-units']) +}) + +it('warns when using max variants with mixed units (with screens config)', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using max variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using min and max variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (max-width: 700rem) { + .max-\[700rem\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) diff --git a/tests/minimum-impact-selector.test.js b/tests/minimum-impact-selector.test.js index ed2fad914..d8292e467 100644 --- a/tests/minimum-impact-selector.test.js +++ b/tests/minimum-impact-selector.test.js @@ -1,32 +1,29 @@ import { elementSelectorParser } from '../src/lib/resolveDefaultsAtRules' -import { crosscheck } from './util/run' -crosscheck(() => { - it.each` - before | after - ${'*'} | ${'*'} - ${'*:hover'} | ${'*'} - ${'* > *'} | ${'* > *'} - ${'.foo'} | ${'.foo'} - ${'.foo:hover'} | ${'.foo'} - ${'.foo:focus:hover'} | ${'.foo'} - ${'li:first-child'} | ${'li'} - ${'li:before'} | ${'li:before'} - ${'li::before'} | ${'li::before'} - ${'#app .foo'} | ${'.foo'} - ${'#app'} | ${'[id=app]'} - ${'#app.other'} | ${'.other'} - ${'input[type="text"]'} | ${'[type="text"]'} - ${'input[type="text"].foo'} | ${'.foo'} - ${'.group .group\\:foo'} | ${'.group\\:foo'} - ${'.group:hover .group-hover\\:foo'} | ${'.group-hover\\:foo'} - ${'.owl > * + *'} | ${'.owl > *'} - ${'.owl > :not([hidden]) + :not([hidden])'} | ${'.owl > *'} - ${'.group:hover .group-hover\\:owl > :not([hidden]) + :not([hidden])'} | ${'.group-hover\\:owl > *'} - ${'.peer:first-child ~ .peer-first\\:shadow-md'} | ${'.peer-first\\:shadow-md'} - ${'.whats ~ .next > span:hover'} | ${'span'} - ${'.foo .bar ~ .baz > .next > span > article:hover'} | ${'article'} - `('should generate "$after" from "$before"', ({ before, after }) => { - expect(elementSelectorParser.transformSync(before).join(', ')).toEqual(after) - }) +it.each` + before | after + ${'*'} | ${'*'} + ${'*:hover'} | ${'*'} + ${'* > *'} | ${'* > *'} + ${'.foo'} | ${'.foo'} + ${'.foo:hover'} | ${'.foo'} + ${'.foo:focus:hover'} | ${'.foo'} + ${'li:first-child'} | ${'li'} + ${'li:before'} | ${'li:before'} + ${'li::before'} | ${'li::before'} + ${'#app .foo'} | ${'.foo'} + ${'#app'} | ${'[id=app]'} + ${'#app.other'} | ${'.other'} + ${'input[type="text"]'} | ${'[type="text"]'} + ${'input[type="text"].foo'} | ${'.foo'} + ${'.group .group\\:foo'} | ${'.group\\:foo'} + ${'.group:hover .group-hover\\:foo'} | ${'.group-hover\\:foo'} + ${'.owl > * + *'} | ${'.owl > *'} + ${'.owl > :not([hidden]) + :not([hidden])'} | ${'.owl > *'} + ${'.group:hover .group-hover\\:owl > :not([hidden]) + :not([hidden])'} | ${'.group-hover\\:owl > *'} + ${'.peer:first-child ~ .peer-first\\:shadow-md'} | ${'.peer-first\\:shadow-md'} + ${'.whats ~ .next > span:hover'} | ${'span'} + ${'.foo .bar ~ .baz > .next > span > article:hover'} | ${'article'} +`('should generate "$after" from "$before"', ({ before, after }) => { + expect(elementSelectorParser.transformSync(before).join(', ')).toEqual(after) }) diff --git a/tests/modify-selectors.test.js b/tests/modify-selectors.test.js index 3176b17f3..e6ce3cf14 100644 --- a/tests/modify-selectors.test.js +++ b/tests/modify-selectors.test.js @@ -1,95 +1,93 @@ import selectorParser from 'postcss-selector-parser' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('modify selectors', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [ - function ({ addVariant }) { - addVariant('foo', ({ modifySelectors, separator }) => { - modifySelectors(({ selector }) => { - return selectorParser((selectors) => { - selectors.walkClasses((classNode) => { - classNode.value = `foo${separator}${classNode.value}` - classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) - }) - }).processSync(selector) - }) +test('modify selectors', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [ + function ({ addVariant }) { + addVariant('foo', ({ modifySelectors, separator }) => { + modifySelectors(({ selector }) => { + return selectorParser((selectors) => { + selectors.walkClasses((classNode) => { + classNode.value = `foo${separator}${classNode.value}` + classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) + }) + }).processSync(selector) }) - }, - ], + }) + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .markdown > p { + margin-top: 12px; + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .markdown > p { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .markdown > p { + margin-top: 12px; + } + .font-bold { + font-weight: 700; + } + .foo .foo\:markdown > p, + .foo .foo\:visited\:markdown:visited > p { + margin-top: 12px; + } + @media (min-width: 1024px) { + .foo .lg\:foo\:disabled\:markdown:disabled > p { margin-top: 12px; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .markdown > p { - margin-top: 12px; - } - .font-bold { + .foo .foo\:font-bold, + .foo .foo\:hover\:font-bold:hover { + font-weight: 700; + } + @media (min-width: 640px) { + .foo .sm\:foo\:font-bold { font-weight: 700; } - .foo .foo\:markdown > p, - .foo .foo\:visited\:markdown:visited > p { - margin-top: 12px; - } - @media (min-width: 1024px) { - .foo .lg\:foo\:disabled\:markdown:disabled > p { - margin-top: 12px; - } - } - .foo .foo\:font-bold, - .foo .foo\:hover\:font-bold:hover { + } + @media (min-width: 768px) { + .foo .md\:foo\:focus\:font-bold:focus { font-weight: 700; } - @media (min-width: 640px) { - .foo .sm\:foo\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .foo .md\:foo\:focus\:font-bold:focus { - font-weight: 700; - } - } - `) - }) + } + `) }) }) diff --git a/tests/mutable.test.js b/tests/mutable.test.js index 45419380f..5c3f9a487 100644 --- a/tests/mutable.test.js +++ b/tests/mutable.test.js @@ -1,54 +1,52 @@ import path from 'path' import postcss from 'postcss' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - function pluginThatMutatesRules() { - return (root) => { - root.walkRules((rule) => { - rule.nodes - .filter((node) => node.prop === 'background-image') - .forEach((node) => { - node.value = 'url("./bar.png")' - }) +function pluginThatMutatesRules() { + return (root) => { + root.walkRules((rule) => { + rule.nodes + .filter((node) => node.prop === 'background-image') + .forEach((node) => { + node.value = 'url("./bar.png")' + }) - return rule - }) - } + return rule + }) + } +} + +test('plugins mutating rules after tailwind doesnt break it', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + backgroundImage: { + foo: 'url("./foo.png")', + }, + }, + plugins: [], } - test('plugins mutating rules after tailwind doesnt break it', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - backgroundImage: { - foo: 'url("./foo.png")', - }, - }, - plugins: [], - } + function checkResult(result) { + expect(result.css).toMatchFormattedCss(css` + .bg-foo { + background-image: url('./foo.png'); + } + `) + } - function checkResult(result) { - expect(result.css).toMatchFormattedCss(css` - .bg-foo { - background-image: url('./foo.png'); - } - `) - } + // Verify the first run produces the expected result + let firstRun = await run('@tailwind utilities', config) + checkResult(firstRun) - // Verify the first run produces the expected result - let firstRun = await run('@tailwind utilities', config) - checkResult(firstRun) - - // Outside of the context of tailwind jit more postcss plugins may operate on the AST: - // In this case we have a plugin that mutates rules directly - await postcss([pluginThatMutatesRules()]).process(firstRun, { - from: path.resolve(__filename), - }) - - // Verify subsequent runs don't produce mutated rules - let secondRun = await run('@tailwind utilities', config) - checkResult(secondRun) + // Outside of the context of tailwind jit more postcss plugins may operate on the AST: + // In this case we have a plugin that mutates rules directly + await postcss([pluginThatMutatesRules()]).process(firstRun, { + from: path.resolve(__filename), }) + + // Verify subsequent runs don't produce mutated rules + let secondRun = await run('@tailwind utilities', config) + checkResult(secondRun) }) diff --git a/tests/negateValue.test.js b/tests/negateValue.test.js index 052132f91..c31741d48 100644 --- a/tests/negateValue.test.js +++ b/tests/negateValue.test.js @@ -1,17 +1,14 @@ import negateValue from '../src/util/negateValue' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it negates numeric CSS values', () => { - expect(negateValue('5')).toEqual('-5') - expect(negateValue('10px')).toEqual('-10px') - expect(negateValue('18rem')).toEqual('-18rem') - expect(negateValue('-10')).toEqual('10') - expect(negateValue('-7ch')).toEqual('7ch') - }) - - test('values that cannot be negated become undefined', () => { - expect(negateValue('auto')).toBeUndefined() - expect(negateValue('cover')).toBeUndefined() - }) +test('it negates numeric CSS values', () => { + expect(negateValue('5')).toEqual('-5') + expect(negateValue('10px')).toEqual('-10px') + expect(negateValue('18rem')).toEqual('-18rem') + expect(negateValue('-10')).toEqual('10') + expect(negateValue('-7ch')).toEqual('7ch') +}) + +test('values that cannot be negated become undefined', () => { + expect(negateValue('auto')).toBeUndefined() + expect(negateValue('cover')).toBeUndefined() }) diff --git a/tests/negated-content.test.js b/tests/negated-content.test.js index 66e231946..6d46e3a8d 100644 --- a/tests/negated-content.test.js +++ b/tests/negated-content.test.js @@ -1,29 +1,27 @@ import * as path from 'path' -import { crosscheck, run, css, defaults } from './util/run' +import { run, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to use negated content patterns', () => { - let config = { - content: [ - path.resolve(__dirname, './negated-content-*.test.html'), - '!' + path.resolve(__dirname, './negated-content-ignore.test.html'), - ], - corePlugins: { preflight: false }, - } +it('should be possible to use negated content patterns', () => { + let config = { + content: [ + path.resolve(__dirname, './negated-content-*.test.html'), + '!' + path.resolve(__dirname, './negated-content-ignore.test.html'), + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .uppercase { - text-transform: uppercase; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .uppercase { + text-transform: uppercase; + } + `) }) }) diff --git a/tests/negative-prefix.test.js b/tests/negative-prefix.test.js index c799bb54e..615558807 100644 --- a/tests/negative-prefix.test.js +++ b/tests/negative-prefix.test.js @@ -1,346 +1,342 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('using a negative prefix with a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 2: '8px', - '-2': '-4px', - }, +test('using a negative prefix with a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 2: '8px', + '-2': '-4px', }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-2 { - margin-top: -4px; - } - .mt-2 { - margin-top: 8px; - } - `) - }) - }) - - test('using a negative scale value with a plugin that does not support dynamic negative values', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - opacity: { - '-50': '0.5', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-opacity-50 { - opacity: 0.5; - } - `) - }) - }) - - test('using a negative prefix without a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: '20px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: -20px; - } - .mt-5 { - margin-top: 20px; - } - `) - }) - }) - - test('being an asshole', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - '-[10px]': '55px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: 55px; - } - `) - }) - }) - - test('being a real asshole', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - '[10px]': '55px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: -55px; - } - `) - }) - }) - - test('a value that includes a variable', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: 'var(--sizing-5)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: calc(var(--sizing-5) * -1); - } - .mt-5 { - margin-top: var(--sizing-5); - } - `) - }) - }) - - test('a value that includes a calc', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: 'calc(52px * -3)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: 156px; - } - .mt-5 { - margin-top: -156px; - } - `) - }) - }) - - test('a value that includes min/max/clamp functions', () => { - let config = { - content: [ - { raw: html`
` }, - ], - theme: { - margin: { - min: 'min(100vmin, 3rem)', - max: 'max(100vmax, 3rem)', - clamp: 'clamp(1rem, 100vh, 3rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-clamp { - margin-top: calc(-1 * clamp(1rem, 100vh, 3rem)); - } - .-mt-max { - margin-top: calc(-1 * max(100vmax, 3rem)); - } - .-mt-min { - margin-top: calc(-1 * min(100vmin, 3rem)); - } - .mt-clamp { - margin-top: clamp(1rem, 100vh, 3rem); - } - .mt-max { - margin-top: max(100vmax, 3rem); - } - .mt-min { - margin-top: min(100vmin, 3rem); - } - `) - }) - }) - - test('a keyword value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - auto: 'auto', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .mt-auto { - margin-top: auto; - } - `) - }) - }) - - test('a zero value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 0: '0', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-0, - .mt-0 { - margin-top: 0; - } - `) - }) - }) - - test('a color', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - red: 'red', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) - }) - }) - - test('arbitrary values', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: -10px; - } - `) - }) - }) - - test('negating a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - weird: '-15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-weird { - margin-top: 15px; - } - `) - }) - }) - - test('negating a default value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt { - margin-top: -15px; - } - `) - }) - }) - - test('using a negative prefix with a negative default scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '8px', - '-DEFAULT': '-4px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt { - margin-top: -4px; - } - .mt { - margin-top: 8px; - } - `) - }) - }) - - test('negating a default value with a configured prefix', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .tw--mt { - margin-top: -15px; - } - `) - }) - }) - - test('arbitrary value keywords should be ignored', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-2 { + margin-top: -4px; + } + .mt-2 { + margin-top: 8px; + } + `) + }) +}) + +test('using a negative scale value with a plugin that does not support dynamic negative values', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + opacity: { + '-50': '0.5', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-opacity-50 { + opacity: 0.5; + } + `) + }) +}) + +test('using a negative prefix without a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: '20px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-5 { + margin-top: -20px; + } + .mt-5 { + margin-top: 20px; + } + `) + }) +}) + +test('being an asshole', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + '-[10px]': '55px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-\[10px\] { + margin-top: 55px; + } + `) + }) +}) + +test('being a real asshole', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + '[10px]': '55px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-\[10px\] { + margin-top: -55px; + } + `) + }) +}) + +test('a value that includes a variable', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: 'var(--sizing-5)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-5 { + margin-top: calc(var(--sizing-5) * -1); + } + .mt-5 { + margin-top: var(--sizing-5); + } + `) + }) +}) + +test('a value that includes a calc', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: 'calc(52px * -3)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-5 { + margin-top: 156px; + } + .mt-5 { + margin-top: -156px; + } + `) + }) +}) + +test('a value that includes min/max/clamp functions', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + min: 'min(100vmin, 3rem)', + max: 'max(100vmax, 3rem)', + clamp: 'clamp(1rem, 100vh, 3rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-clamp { + margin-top: calc(-1 * clamp(1rem, 100vh, 3rem)); + } + .-mt-max { + margin-top: calc(-1 * max(100vmax, 3rem)); + } + .-mt-min { + margin-top: calc(-1 * min(100vmin, 3rem)); + } + .mt-clamp { + margin-top: clamp(1rem, 100vh, 3rem); + } + .mt-max { + margin-top: max(100vmax, 3rem); + } + .mt-min { + margin-top: min(100vmin, 3rem); + } + `) + }) +}) + +test('a keyword value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + auto: 'auto', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .mt-auto { + margin-top: auto; + } + `) + }) +}) + +test('a zero value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 0: '0', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-0, + .mt-0 { + margin-top: 0; + } + `) + }) +}) + +test('a color', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + red: 'red', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) + }) +}) + +test('arbitrary values', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-\[10px\] { + margin-top: -10px; + } + `) + }) +}) + +test('negating a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + weird: '-15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt-weird { + margin-top: 15px; + } + `) + }) +}) + +test('negating a default value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt { + margin-top: -15px; + } + `) + }) +}) + +test('using a negative prefix with a negative default scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '8px', + '-DEFAULT': '-4px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-mt { + margin-top: -4px; + } + .mt { + margin-top: 8px; + } + `) + }) +}) + +test('negating a default value with a configured prefix', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .tw--mt { + margin-top: -15px; + } + `) + }) +}) + +test('arbitrary value keywords should be ignored', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) }) }) diff --git a/tests/normalize-config.test.js b/tests/normalize-config.test.js index a0b7a59bb..0468c8c78 100644 --- a/tests/normalize-config.test.js +++ b/tests/normalize-config.test.js @@ -1,164 +1,155 @@ import { normalizeConfig } from '../src/util/normalizeConfig' import resolveConfig from '../src/public/resolve-config' -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it.each` - config - ${{ purge: [{ raw: 'text-center' }] }} - ${{ purge: { content: [{ raw: 'text-center' }] } }} - ${{ content: { content: [{ raw: 'text-center' }] } }} - `('should normalize content $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - `) - }) - }) - - it.each` - config - ${{ purge: { safelist: ['text-center'] } }} - ${{ purge: { options: { safelist: ['text-center'] } } }} - ${{ content: { safelist: ['text-center'] } }} - `('should normalize safelist $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - `) - }) - }) - - oxide.test.todo('should normalize extractors') - stable.test.each` - config - ${{ content: [{ raw: 'text-center' }], purge: { extract: () => ['font-bold'] } }} - ${{ content: [{ raw: 'text-center' }], purge: { extract: { DEFAULT: () => ['font-bold'] } } }} - ${{ - content: [{ raw: 'text-center' }], - purge: { options: { defaultExtractor: () => ['font-bold'] } }, - }} - ${{ - content: [{ raw: 'text-center' }], - purge: { - options: { extractors: [{ extractor: () => ['font-bold'], extensions: ['html'] }] }, - }, - }} - ${{ content: [{ raw: 'text-center' }], purge: { extract: { html: () => ['font-bold'] } } }} - `('should normalize extractors $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - `) - }) - }) - - oxide.test.todo('should still be possible to use the "old" v2 config') - stable.test('should still be possible to use the "old" v2 config', () => { - let config = { - purge: { - content: [ - { raw: 'text-svelte', extension: 'svelte' }, - { raw: '# My Big Heading', extension: 'md' }, - ], - options: { - defaultExtractor(content) { - return content.split(' ').concat(['font-bold']) - }, - }, - extract: { - svelte(content) { - return content.replace('svelte', 'center').split(' ') - }, - }, - transform: { - md() { - return 'text-4xl' - }, - }, - }, - theme: { - extends: {}, - }, - variants: { - extends: {}, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - .text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; - } - .font-bold { - font-weight: 700; - } - `) - }) - }) - - it('should keep content files with globs', () => { - let config = { - content: ['./example-folder/**/*.{html,js}'], - } - - stable.expect(normalizeConfig(resolveConfig(config)).content).toEqual({ - files: ['./example-folder/**/*.{html,js}'], - relative: false, - extract: {}, - transform: {}, - }) - oxide.expect(normalizeConfig(resolveConfig(config)).content).toEqual({ - files: ['./example-folder/**/*.{html,js}'], - relative: true, - extract: {}, - transform: {}, - }) - }) - - it('should warn when we detect invalid globs with incorrect brace expansion', () => { - let config = { - content: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - } - - let normalizedConfig = normalizeConfig(resolveConfig(config)).content - - // No rewrite happens - stable.expect(normalizedConfig).toEqual({ - files: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - relative: false, - extract: {}, - transform: {}, - }) - oxide.expect(normalizedConfig).toEqual({ - files: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - relative: true, - extract: {}, - transform: {}, - }) - - expect().toHaveBeenWarnedWith(['invalid-glob-braces']) +it.each` + config + ${{ purge: [{ raw: 'text-center' }] }} + ${{ purge: { content: [{ raw: 'text-center' }] } }} + ${{ content: { files: [], content: [{ raw: 'text-center' }] } }} +`('should normalize content $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + `) }) }) + +it.each` + config + ${{ purge: { safelist: ['text-center'] } }} + ${{ purge: { options: { safelist: ['text-center'] } } }} + ${{ content: { files: [], safelist: ['text-center'] } }} +`('should normalize safelist $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + `) + }) +}) + +test.each` + config + ${{ + purge: { content: [{ raw: 'text-center' }], extract: () => ['font-bold'] }, +}} + ${{ + purge: { content: [{ raw: 'text-center' }], extract: { DEFAULT: () => ['font-bold'] } }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + options: { defaultExtractor: () => ['font-bold'] }, + }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + options: { extractors: [{ extractor: () => ['font-bold'], extensions: ['html'] }] }, + }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + extract: { html: () => ['font-bold'] }, + }, +}} +`('should normalize extractors $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + `) + }) +}) + +test('should still be possible to use the "old" v2 config', () => { + let config = { + purge: { + content: [ + { raw: 'text-svelte', extension: 'svelte' }, + { raw: '# My Big Heading', extension: 'md' }, + ], + options: { + defaultExtractor(content) { + return content.split(' ').concat(['font-bold']) + }, + }, + extract: { + svelte(content) { + return content.replace('svelte', 'center').split(' ') + }, + }, + transform: { + md() { + return 'text-4xl' + }, + }, + }, + theme: { + extends: {}, + }, + variants: { + extends: {}, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + .text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; + } + .font-bold { + font-weight: 700; + } + `) + }) +}) + +it('should keep content files with globs', () => { + let config = { + content: ['./example-folder/**/*.{html,js}'], + } + + expect(normalizeConfig(resolveConfig(config)).content).toEqual({ + files: ['./example-folder/**/*.{html,js}'], + relative: false, + extract: {}, + transform: {}, + }) +}) + +it('should warn when we detect invalid globs with incorrect brace expansion', () => { + let config = { + content: [ + './{example-folder}/**/*.{html,js}', + './{example-folder}/**/*.{html}', + './example-folder/**/*.{html}', + ], + } + + let normalizedConfig = normalizeConfig(resolveConfig(config)).content + + // No rewrite happens + expect(normalizedConfig).toEqual({ + files: [ + './{example-folder}/**/*.{html,js}', + './{example-folder}/**/*.{html}', + './example-folder/**/*.{html}', + ], + relative: false, + extract: {}, + transform: {}, + }) + + expect().toHaveBeenWarnedWith(['invalid-glob-braces']) +}) diff --git a/tests/normalize-data-types.test.js b/tests/normalize-data-types.test.js index eff2fa677..d99ce1c18 100644 --- a/tests/normalize-data-types.test.js +++ b/tests/normalize-data-types.test.js @@ -1,5 +1,4 @@ import { normalize } from '../src/util/dataTypes' -import { crosscheck } from './util/run' let table = [ ['foo', 'foo'], @@ -47,8 +46,6 @@ let table = [ ['color(0_0_0_/_1.0)', 'color(0 0 0 / 1.0)'], ] -crosscheck(() => { - it.each(table)('normalize data: %s', (input, output) => { - expect(normalize(input)).toBe(output) - }) +it.each(table)('normalize data: %s', (input, output) => { + expect(normalize(input)).toBe(output) }) diff --git a/tests/normalize-screens.test.js b/tests/normalize-screens.test.js index 464623f9f..da31c50d3 100644 --- a/tests/normalize-screens.test.js +++ b/tests/normalize-screens.test.js @@ -1,66 +1,63 @@ import { normalizeScreens } from '../src/util/normalizeScreens' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should normalize an array of string values', () => { - let screens = ['768px', '1200px'] +it('should normalize an array of string values', () => { + let screens = ['768px', '1200px'] - expect(normalizeScreens(screens)).toEqual([ - { name: '768px', not: false, values: [{ min: '768px', max: undefined }] }, - { name: '1200px', not: false, values: [{ min: '1200px', max: undefined }] }, - ]) - }) - - it('should normalize an object with string values', () => { - let screens = { - a: '768px', - b: '1200px', - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: '1200px', max: undefined }] }, - ]) - }) - - it('should normalize an object with object values', () => { - let screens = { - a: { min: '768px' }, - b: { max: '1200px' }, - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, - ]) - }) - - it('should normalize an object with multiple object values', () => { - let screens = { - a: [{ min: '768px' }, { max: '1200px' }], - } - - expect(normalizeScreens(screens)).toEqual([ - { - name: 'a', - not: false, - values: [ - { max: undefined, min: '768px', raw: undefined }, - { max: '1200px', min: undefined, raw: undefined }, - ], - }, - ]) - }) - - it('should normalize an object with object values (min-width normalized to width)', () => { - let screens = { - a: { 'min-width': '768px' }, - b: { max: '1200px' }, - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, - ]) - }) + expect(normalizeScreens(screens)).toEqual([ + { name: '768px', not: false, values: [{ min: '768px', max: undefined }] }, + { name: '1200px', not: false, values: [{ min: '1200px', max: undefined }] }, + ]) +}) + +it('should normalize an object with string values', () => { + let screens = { + a: '768px', + b: '1200px', + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: '1200px', max: undefined }] }, + ]) +}) + +it('should normalize an object with object values', () => { + let screens = { + a: { min: '768px' }, + b: { max: '1200px' }, + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, + ]) +}) + +it('should normalize an object with multiple object values', () => { + let screens = { + a: [{ min: '768px' }, { max: '1200px' }], + } + + expect(normalizeScreens(screens)).toEqual([ + { + name: 'a', + not: false, + values: [ + { max: undefined, min: '768px', raw: undefined }, + { max: '1200px', min: undefined, raw: undefined }, + ], + }, + ]) +}) + +it('should normalize an object with object values (min-width normalized to width)', () => { + let screens = { + a: { 'min-width': '768px' }, + b: { max: '1200px' }, + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, + ]) }) diff --git a/tests/opacity.test.js b/tests/opacity.test.js index 82b437ce8..4b2b0eadf 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -1,1115 +1,1047 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('opacity', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, +test('opacity', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-black > :not([hidden]) ~ :not([hidden]), - .border-black { - border-color: #000; - } - .bg-black { - background-color: #000; - } - .text-black, - .placeholder-black::placeholder { - color: #000; - } - `) - }) - }) - - test('colors defined as functions work when opacity plugins are disabled', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: ({ opacityValue }) => - opacityValue === undefined - ? 'rgb(var(--color-primary))' - : `rgb(var(--color-primary) / ${opacityValue})`, - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: rgb(var(--color-primary)); - } - .bg-primary { - background-color: rgb(var(--color-primary)); - } - .text-primary, - .placeholder-primary::placeholder { - color: rgb(var(--color-primary)); - } - `) - }) - }) - - it('can use defining custom properties for colors (opacity plugins enabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(var(--color-primary) / var(--tw-divide-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-primary { - --tw-border-opacity: 1; - border-color: rgb(var(--color-primary) / var(--tw-border-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-primary { - --tw-text-opacity: 1; - color: rgb(var(--color-primary) / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-primary::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(var(--color-primary) / var(--tw-placeholder-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-primary { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(var(--color-primary) / var(--tw-ring-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: rgb(var(--color-primary) / 1); - } - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - .text-primary, - .placeholder-primary::placeholder { - color: rgb(var(--color-primary) / 1); - } - .ring-primary { - --tw-ring-color: rgb(var(--color-primary) / 1); - } - `) - }) - }) - - it('can use rgb helper when defining custom properties for colors (opacity plugins disabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - ringOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(var(--color-primary) / 1); - } - .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(var(--color-primary) / 0.5); - } - .border-primary { - border-color: rgb(var(--color-primary) / 1); - } - .border-primary\/50 { - border-color: rgb(var(--color-primary) / 0.5); - } - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - .bg-primary\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - .text-primary { - color: rgb(var(--color-primary) / 1); - } - .text-primary\/50 { - color: rgb(var(--color-primary) / 0.5); - } - .placeholder-primary::placeholder { - color: rgb(var(--color-primary) / 1); - } - .placeholder-primary\/50::placeholder { - color: rgb(var(--color-primary) / 0.5); - } - .ring-primary { - --tw-ring-color: rgb(var(--color-primary) / 1); - } - .ring-primary\/50 { - --tw-ring-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('can use hsl helper when defining custom properties for colors (opacity plugins enabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'hsl(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: hsl(var(--color-primary) / var(--tw-divide-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-primary { - --tw-border-opacity: 1; - border-color: hsl(var(--color-primary) / var(--tw-border-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-primary { - --tw-bg-opacity: 1; - background-color: hsl(var(--color-primary) / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-primary { - --tw-text-opacity: 1; - color: hsl(var(--color-primary) / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-primary::placeholder { - --tw-placeholder-opacity: 1; - color: hsl(var(--color-primary) / var(--tw-placeholder-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-primary { - --tw-ring-opacity: 1; - --tw-ring-color: hsl(var(--color-primary) / var(--tw-ring-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: hsl(var(--color-primary) / 1); - } - .bg-primary { - background-color: hsl(var(--color-primary) / 1); - } - .text-primary, - .placeholder-primary::placeholder { - color: hsl(var(--color-primary) / 1); - } - .ring-primary { - --tw-ring-color: hsl(var(--color-primary) / 1); - } - `) - }) - }) - - it('can use hsl helper when defining custom properties for colors (opacity plugins disabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'hsl(var(--color-primary) / )', - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - ringOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - border-color: hsl(var(--color-primary) / 1); - } - .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: hsl(var(--color-primary) / 0.5); - } - .border-primary { - border-color: hsl(var(--color-primary) / 1); - } - .border-primary\/50 { - border-color: hsl(var(--color-primary) / 0.5); - } - .bg-primary { - background-color: hsl(var(--color-primary) / 1); - } - .bg-primary\/50 { - background-color: hsl(var(--color-primary) / 0.5); - } - .text-primary { - color: hsl(var(--color-primary) / 1); - } - .text-primary\/50 { - color: hsl(var(--color-primary) / 0.5); - } - .placeholder-primary::placeholder { - color: hsl(var(--color-primary) / 1); - } - .placeholder-primary\/50::placeholder { - color: hsl(var(--color-primary) / 0.5); - } - .ring-primary { - --tw-ring-color: hsl(var(--color-primary) / 1); - } - .ring-primary\/50 { - --tw-ring-color: hsl(var(--color-primary) / 0.5); - } - `) - }) - }) - - test('Theme function in JS can apply alpha values to colors (1)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3b82f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (2)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3b82f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 0.5'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (3)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: rgb(59 130 246 / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (4)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3c83f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (5)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3c83f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 0.5'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (6)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: hsl(217 91% 60% / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (7)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: rgb(var(--foo) / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function prefers existing values in config', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: purple; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { - blue: { - '500 / 50%': 'purple', - }, - }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - it('should be possible to use an as part of the color definition', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); - } - `) - }) - }) - - it('should be possible to use an as part of the color definition with an opacity modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('should be possible to use an as part of the color definition with an opacity modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - `) - }) - }) - - it('should be possible to use inside arbitrary values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[rgb\(var\(--color-primary\)\/\\)\]\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('Theme functions can reference values with slashes in brackets', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - colors: { - 'a/b': '#000000', - }, - extend: { - backgroundColor: ({ theme }) => ({ - foo1: theme('colors[a/b]'), - foo2: theme('colors[a/b]/50%'), - }), - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-foo1 { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .bg-foo2 { - background-color: #00000080; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-foo1 { - background-color: #000; - } - .bg-foo2 { - background-color: #00000080; - } - `) - }) - }) - - it('works with opacity values defined as a placeholder or a function in when colors is a function', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - theme: { - colors: () => ({ - foobar1: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, - foobar2: `rgb(255 100 0 / )`, - foobar3: { - 100: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, - 200: `rgb(255 100 0 / )`, - }, - }), - extend: { - backgroundColor: ({ theme }) => ({ - foo10: theme('colors.foobar1'), - foo20: theme('colors.foobar2'), - foo30: theme('colors.foobar3.100'), - foo40: theme('colors.foobar3.200'), - foo11: theme('colors.foobar1 / 50%'), - foo21: theme('colors.foobar2 / 50%'), - foo31: theme('colors.foobar3.100 / 50%'), - foo41: theme('colors.foobar3.200 / 50%'), - }), - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-foo10 { - background-color: #ff6400; - } - .bg-foo11 { - background-color: #ff640080; - } - .bg-foo20 { - --tw-bg-opacity: 1; - background-color: rgb(255 100 0 / var(--tw-bg-opacity)); - } - .bg-foo21 { - background-color: #ff640080; - } - .bg-foo30 { - background-color: #ff6400; - } - .bg-foo31 { - background-color: #ff640080; - } - .bg-foo40 { - --tw-bg-opacity: 1; - background-color: rgb(255 100 0 / var(--tw-bg-opacity)); - } - .bg-foo41 { - background-color: #ff640080; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-foo10 { - background-color: #ff6400; - } - .bg-foo11 { - background-color: #ff640080; - } - .bg-foo20 { - background-color: #ff6400; - } - .bg-foo21 { - background-color: #ff640080; - } - .bg-foo30 { - background-color: #ff6400; - } - .bg-foo31 { - background-color: #ff640080; - } - .bg-foo40 { - background-color: #ff6400; - } - .bg-foo41 { - background-color: #ff640080; - } - `) - }) - }) - - it('The disableColorOpacityUtilitiesByDefault flag disables the color opacity plugins and removes their variables', () => { - let config = { - future: { - disableColorOpacityUtilitiesByDefault: true, - }, - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd; - } - .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd80; - } - .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .border-blue-300 { - border-color: #93c5fd; - } - .border-blue-300\/50 { - border-color: #93c5fd80; - } - .border-blue-300\/\[var\(--my-opacity\)\] { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .bg-blue-300 { - background-color: #93c5fd; - } - .bg-blue-300\/50 { - background-color: #93c5fd80; - } - .bg-blue-300\/\[var\(--my-opacity\)\] { - background-color: rgb(147 197 253 / var(--my-opacity)); - } - .text-blue-300 { - color: #93c5fd; - } - .text-blue-300\/50 { - color: #93c5fd80; - } - .text-blue-300\/\[var\(--my-opacity\)\] { - color: rgb(147 197 253 / var(--my-opacity)); - } - .placeholder-blue-300::placeholder { - color: #93c5fd; - } - .placeholder-blue-300\/50::placeholder { - color: #93c5fd80; - } - .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { - color: rgb(147 197 253 / var(--my-opacity)); - } - .ring-blue-300 { - --tw-ring-color: #93c5fd; - } - .ring-blue-300\/50 { - --tw-ring-color: #93c5fd80; - } - .ring-blue-300\/\[var\(--my-opacity\)\] { - --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); - } - `) - }) - }) - - it('You can re-enable any opacity plugin even when disableColorOpacityUtilitiesByDefault is enabled', () => { - let config = { - future: { - disableColorOpacityUtilitiesByDefault: true, - }, - corePlugins: { - backgroundOpacity: true, - borderOpacity: true, - divideOpacity: true, - placeholderOpacity: true, - ringOpacity: true, - textOpacity: true, - }, - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-divide-opacity)); - } - .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd80; - } - .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-blue-300 { - --tw-border-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-border-opacity)); - } - .border-blue-300\/50 { - border-color: #93c5fd80; - } - .border-blue-300\/\[var\(--my-opacity\)\] { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-blue-300 { - --tw-bg-opacity: 1; - background-color: rgb(147 197 253 / var(--tw-bg-opacity)); - } - .bg-blue-300\/50 { - background-color: #93c5fd80; - } - .bg-blue-300\/\[var\(--my-opacity\)\] { - background-color: rgb(147 197 253 / var(--my-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-blue-300 { - --tw-text-opacity: 1; - color: rgb(147 197 253 / var(--tw-text-opacity)); - } - .text-blue-300\/50 { - color: #93c5fd80; - } - .text-blue-300\/\[var\(--my-opacity\)\] { - color: rgb(147 197 253 / var(--my-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-blue-300::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(147 197 253 / var(--tw-placeholder-opacity)); - } - .placeholder-blue-300\/50::placeholder { - color: #93c5fd80; - } - .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { - color: rgb(147 197 253 / var(--my-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-blue-300 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); - } - .ring-blue-300\/50 { - --tw-ring-color: #93c5fd80; - } - .ring-blue-300\/\[var\(--my-opacity\)\] { - --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - }) - }) - - it('can replace the potential alpha value in rgba/hsla syntax', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - 'primary-rgba': 'rgba(var(--color), 0.1)', - 'primary-hsla': 'hsla(var(--color), 0.1)', - }, - }, - } - - let result = await run('@tailwind utilities', config) + ], + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + }, + } + return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .text-primary-hsla\/50 { - color: hsla(var(--color), 0.5); + .divide-black > :not([hidden]) ~ :not([hidden]), + .border-black { + border-color: #000; } - .text-primary-rgba\/50 { - color: rgba(var(--color), 0.5); + .bg-black { + background-color: #000; + } + .text-black, + .placeholder-black::placeholder { + color: #000; } `) }) }) + +test('colors defined as functions work when opacity plugins are disabled', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: ({ opacityValue }) => + opacityValue === undefined + ? 'rgb(var(--color-primary))' + : `rgb(var(--color-primary) / ${opacityValue})`, + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]), + .border-primary { + border-color: rgb(var(--color-primary)); + } + .bg-primary { + background-color: rgb(var(--color-primary)); + } + .text-primary, + .placeholder-primary::placeholder { + color: rgb(var(--color-primary)); + } + `) + }) +}) + +it('can use defining custom properties for colors (opacity plugins enabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(var(--color-primary) / var(--tw-divide-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-primary { + --tw-border-opacity: 1; + border-color: rgb(var(--color-primary) / var(--tw-border-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-primary { + --tw-bg-opacity: 1; + background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-primary { + --tw-text-opacity: 1; + color: rgb(var(--color-primary) / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-primary::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(var(--color-primary) / var(--tw-placeholder-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-primary { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(var(--color-primary) / var(--tw-ring-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can use rgb helper when defining custom properties for colors (opacity plugins disabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + ringOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(var(--color-primary) / 1); + } + .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(var(--color-primary) / 0.5); + } + .border-primary { + border-color: rgb(var(--color-primary) / 1); + } + .border-primary\/50 { + border-color: rgb(var(--color-primary) / 0.5); + } + .bg-primary { + background-color: rgb(var(--color-primary) / 1); + } + .bg-primary\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + .text-primary { + color: rgb(var(--color-primary) / 1); + } + .text-primary\/50 { + color: rgb(var(--color-primary) / 0.5); + } + .placeholder-primary::placeholder { + color: rgb(var(--color-primary) / 1); + } + .placeholder-primary\/50::placeholder { + color: rgb(var(--color-primary) / 0.5); + } + .ring-primary { + --tw-ring-color: rgb(var(--color-primary) / 1); + } + .ring-primary\/50 { + --tw-ring-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('can use hsl helper when defining custom properties for colors (opacity plugins enabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'hsl(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: hsl(var(--color-primary) / var(--tw-divide-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-primary { + --tw-border-opacity: 1; + border-color: hsl(var(--color-primary) / var(--tw-border-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-primary { + --tw-bg-opacity: 1; + background-color: hsl(var(--color-primary) / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-primary { + --tw-text-opacity: 1; + color: hsl(var(--color-primary) / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-primary::placeholder { + --tw-placeholder-opacity: 1; + color: hsl(var(--color-primary) / var(--tw-placeholder-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-primary { + --tw-ring-opacity: 1; + --tw-ring-color: hsl(var(--color-primary) / var(--tw-ring-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can use hsl helper when defining custom properties for colors (opacity plugins disabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'hsl(var(--color-primary) / )', + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + ringOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + border-color: hsl(var(--color-primary) / 1); + } + .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: hsl(var(--color-primary) / 0.5); + } + .border-primary { + border-color: hsl(var(--color-primary) / 1); + } + .border-primary\/50 { + border-color: hsl(var(--color-primary) / 0.5); + } + .bg-primary { + background-color: hsl(var(--color-primary) / 1); + } + .bg-primary\/50 { + background-color: hsl(var(--color-primary) / 0.5); + } + .text-primary { + color: hsl(var(--color-primary) / 1); + } + .text-primary\/50 { + color: hsl(var(--color-primary) / 0.5); + } + .placeholder-primary::placeholder { + color: hsl(var(--color-primary) / 1); + } + .placeholder-primary\/50::placeholder { + color: hsl(var(--color-primary) / 0.5); + } + .ring-primary { + --tw-ring-color: hsl(var(--color-primary) / 1); + } + .ring-primary\/50 { + --tw-ring-color: hsl(var(--color-primary) / 0.5); + } + `) + }) +}) + +test('Theme function in JS can apply alpha values to colors (1)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3b82f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (2)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3b82f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (3)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (4)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3c83f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (5)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3c83f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (6)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (7)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', + }, + }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function prefers existing values in config', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: purple; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { + blue: { + '500 / 50%': 'purple', + }, + }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +it('should be possible to use an as part of the color definition', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary { + --tw-bg-opacity: 1; + background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should be possible to use an as part of the color definition with an opacity modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('should be possible to use an as part of the color definition with an opacity modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary { + background-color: rgb(var(--color-primary) / 1); + } + `) + }) +}) + +it('should be possible to use inside arbitrary values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[rgb\(var\(--color-primary\)\/\\)\]\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('Theme functions can reference values with slashes in brackets', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + theme: { + colors: { + 'a/b': '#000000', + }, + extend: { + backgroundColor: ({ theme }) => ({ + foo1: theme('colors[a/b]'), + foo2: theme('colors[a/b]/50%'), + }), + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-foo1 { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .bg-foo2 { + background-color: #00000080; + } + `) + }) +}) + +it('works with opacity values defined as a placeholder or a function in when colors is a function', () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + theme: { + colors: () => ({ + foobar1: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, + foobar2: `rgb(255 100 0 / )`, + foobar3: { + 100: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, + 200: `rgb(255 100 0 / )`, + }, + }), + extend: { + backgroundColor: ({ theme }) => ({ + foo10: theme('colors.foobar1'), + foo20: theme('colors.foobar2'), + foo30: theme('colors.foobar3.100'), + foo40: theme('colors.foobar3.200'), + foo11: theme('colors.foobar1 / 50%'), + foo21: theme('colors.foobar2 / 50%'), + foo31: theme('colors.foobar3.100 / 50%'), + foo41: theme('colors.foobar3.200 / 50%'), + }), + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-foo10 { + background-color: #ff6400; + } + .bg-foo11 { + background-color: #ff640080; + } + .bg-foo20 { + --tw-bg-opacity: 1; + background-color: rgb(255 100 0 / var(--tw-bg-opacity)); + } + .bg-foo21 { + background-color: #ff640080; + } + .bg-foo30 { + background-color: #ff6400; + } + .bg-foo31 { + background-color: #ff640080; + } + .bg-foo40 { + --tw-bg-opacity: 1; + background-color: rgb(255 100 0 / var(--tw-bg-opacity)); + } + .bg-foo41 { + background-color: #ff640080; + } + `) + }) +}) + +it('The disableColorOpacityUtilitiesByDefault flag disables the color opacity plugins and removes their variables', () => { + let config = { + future: { + disableColorOpacityUtilitiesByDefault: true, + }, + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd; + } + .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd80; + } + .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .border-blue-300 { + border-color: #93c5fd; + } + .border-blue-300\/50 { + border-color: #93c5fd80; + } + .border-blue-300\/\[var\(--my-opacity\)\] { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .bg-blue-300 { + background-color: #93c5fd; + } + .bg-blue-300\/50 { + background-color: #93c5fd80; + } + .bg-blue-300\/\[var\(--my-opacity\)\] { + background-color: rgb(147 197 253 / var(--my-opacity)); + } + .text-blue-300 { + color: #93c5fd; + } + .text-blue-300\/50 { + color: #93c5fd80; + } + .text-blue-300\/\[var\(--my-opacity\)\] { + color: rgb(147 197 253 / var(--my-opacity)); + } + .placeholder-blue-300::placeholder { + color: #93c5fd; + } + .placeholder-blue-300\/50::placeholder { + color: #93c5fd80; + } + .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { + color: rgb(147 197 253 / var(--my-opacity)); + } + .ring-blue-300 { + --tw-ring-color: #93c5fd; + } + .ring-blue-300\/50 { + --tw-ring-color: #93c5fd80; + } + .ring-blue-300\/\[var\(--my-opacity\)\] { + --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); + } + `) + }) +}) + +it('You can re-enable any opacity plugin even when disableColorOpacityUtilitiesByDefault is enabled', () => { + let config = { + future: { + disableColorOpacityUtilitiesByDefault: true, + }, + corePlugins: { + backgroundOpacity: true, + borderOpacity: true, + divideOpacity: true, + placeholderOpacity: true, + ringOpacity: true, + textOpacity: true, + }, + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-divide-opacity)); + } + .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd80; + } + .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-blue-300 { + --tw-border-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-border-opacity)); + } + .border-blue-300\/50 { + border-color: #93c5fd80; + } + .border-blue-300\/\[var\(--my-opacity\)\] { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-blue-300 { + --tw-bg-opacity: 1; + background-color: rgb(147 197 253 / var(--tw-bg-opacity)); + } + .bg-blue-300\/50 { + background-color: #93c5fd80; + } + .bg-blue-300\/\[var\(--my-opacity\)\] { + background-color: rgb(147 197 253 / var(--my-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-blue-300 { + --tw-text-opacity: 1; + color: rgb(147 197 253 / var(--tw-text-opacity)); + } + .text-blue-300\/50 { + color: #93c5fd80; + } + .text-blue-300\/\[var\(--my-opacity\)\] { + color: rgb(147 197 253 / var(--my-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-blue-300::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(147 197 253 / var(--tw-placeholder-opacity)); + } + .placeholder-blue-300\/50::placeholder { + color: #93c5fd80; + } + .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { + color: rgb(147 197 253 / var(--my-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-blue-300 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); + } + .ring-blue-300\/50 { + --tw-ring-color: #93c5fd80; + } + .ring-blue-300\/\[var\(--my-opacity\)\] { + --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can replace the potential alpha value in rgba/hsla syntax', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + 'primary-rgba': 'rgba(var(--color), 0.1)', + 'primary-hsla': 'hsla(var(--color), 0.1)', + }, + }, + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchFormattedCss(css` + .text-primary-hsla\/50 { + color: hsla(var(--color), 0.5); + } + .text-primary-rgba\/50 { + color: rgba(var(--color), 0.5); + } + `) +}) diff --git a/tests/oxide.test.js b/tests/oxide.test.js deleted file mode 100644 index d2a697626..000000000 --- a/tests/oxide.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { crosscheck, run, html, css, defaults } from './util/run' - -crosscheck(({ stable, oxide }) => { - stable.test.todo('space-x uses physical properties') - oxide.test('space-x uses logical properties', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); - } - `) - }) - }) -}) diff --git a/tests/parallel-variants.test.js b/tests/parallel-variants.test.js index a4d4dfc8f..61fb2cb33 100644 --- a/tests/parallel-variants.test.js +++ b/tests/parallel-variants.test.js @@ -1,138 +1,136 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic parallel variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', ['& *::test', '&::test']) - }, - ], - } +test('basic parallel variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', ['& *::test', '&::test']) + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) - }) - - test('parallel variants can be generated using a function that returns parallel variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', () => ['& *::test', '&::test']) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) - }) - - test('a function that returns parallel variants can modify the container', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', ({ container }) => { - container.walkDecls((decl) => { - decl.value = `calc(0 + ${decl.value})` - }) - - return ['& *::test', '&::test'] - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) + }) +}) + +test('parallel variants can be generated using a function that returns parallel variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', () => ['& *::test', '&::test']) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) + }) +}) + +test('a function that returns parallel variants can modify the container', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', ({ container }) => { + container.walkDecls((decl) => { + decl.value = `calc(0 + ${decl.value})` + }) + + return ['& *::test', '&::test'] + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) }) }) diff --git a/tests/parse-candidate-strings.test.js b/tests/parse-candidate-strings.test.js new file mode 100644 index 000000000..a97d66846 --- /dev/null +++ b/tests/parse-candidate-strings.test.js @@ -0,0 +1,441 @@ +import { parseCandidateStrings, IO, Parsing } from '@tailwindcss/oxide' +import { defaultExtractor as createDefaultExtractor } from '../src/lib/defaultExtractor' + +let html = String.raw + +let defaultExtractor = createDefaultExtractor({ tailwindConfig: { separator: ':' } }) + +function regexParser(str) { + return defaultExtractor(str) +} + +function oxideParser(str) { + return parseCandidateStrings( + [{ content: str, extension: 'html' }], + IO.Sequential | Parsing.Parallel + ) +} + +function templateTable(classes) { + classes = classes.concat( + // Variants + classes.flatMap((c) => { + return [ + // Simple variant + `hover:${c}`, + + // Combined variant + `focus:hover:${c}`, + + // Variant with dashes + `group-hover:group-focus:${c}`, + + // With special characters + `:${c}`, + + // With arbitrary values + `min-[300px]:${c}`, + + // With arbitrary values + `[@media(hover:hover)]:${c}`, + + // With parent selector + `[.foo_&]:${c}`, + ] + }) + ) + + let classString = classes.join(' ') + let singleQuoteArraySyntaxWithSpace = `'${classes.join("', '")}'` + let singleQuoteArraySyntaxWithoutSpace = `'${classes.join("','")}'` + + return [ + ['Plain', classString], + ['HTML', html`
`], + + ['JavaScript variable', `let foo = "${classString}"`], + ['JavaScript expression', `document.body.classList.add(['${classString}'].join(' '))`], + ['JavaScript object key', `let foo = {'${classString}': true}`], + + ['JSX basic', html`
`], + ['JSX with JavaScript expression', html`
`], + + ['Vue basic', html`
`], + [ + 'Vue array (single quote, with space)', + html`
`, + ], + [ + 'Vue array (single quote, without space)', + html`
`, + ], + ['Vue object (single quote)', html`
`], + + ['Markdown code fences', ``], + ].map(([name, template]) => [name, template, classes]) +} + +describe.each([ + ['Regex', regexParser], + ['Oxide', oxideParser], +])('%s parser', (_, parse) => { + describe('basic utility classes', () => { + let classes = [ + // One word classes + 'underline', + + // With dashes + 'text-center', + 'pointer-events-none', + + // With numbers + 'px-4', + + // With special characters + 'px-1.5', + 'translate-x-1/2', + 'from-50%', + + // With negative signs + '-translate-x-full', + + // With halves and negative signs + '-translate-x-1/2', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with arbitrary values', () => { + let classes = [ + // With simple number + 'px-[0]', + 'px-[0.5]', + + // With number and unit + 'px-[123px]', + 'px-[123.45px]', + + // With special symbols + 'bg-[#bada55]', + // ^ + 'bg-[color:#bada55]', + // ^^ + 'content-[>]', + // ^ + 'content-[<]', + // ^ + + // With functions and math expressions + 'px-[calc(100%-1rem)]', + 'px-[theme(spacing.1)]', + 'px-[theme(spacing[1.5])]', + + // With spaces (replaced by `_`) + 'bg-[rgb(255_0_0)]', + + // Examples with combinations + 'w-[calc(100%_-_theme("spacing[1.5]))"]', + 'fill-[oklab(59.69%_0.1007_0.1191_/_0.5)]/[33.7%]', + 'fill-[color:oklab(59.69%_0.1007_0.1191_/_0.5)]/[33.7%]', + 'shadow-[inset_0_-3em_3em_rgba(0,_0,_0,_0.1),_0_0_0_2px_rgb(255,_255,_255),_0.3em_0.3em_1em_rgba(0,_0,_0,_0.3)]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + // TODO: This is a bug in the RegEx parser. + if (!extractions.includes(c) && parse === regexParser) { + continue + } + + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with modifiers', () => { + let classes = [ + // With simple modifiers + 'bg-red-500/50', + + // With arbitrary modifiers + 'bg-red-500/[0.5]', + 'bg-red-500/[50%]', + 'bg-red-500/[var(--opacity)]', + + // With spces (replaced by `_`) + 'bg-red-500/[var(--opacity,_50%)]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with important modifier', () => { + let classes = ['!bg-red-500', '!bg-[#bada55]', '![display:flex]', '!-translate-x-1/2'] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + // TODO: This is a bug in the RegEx parser. + if (!extractions.includes(c) && parse === regexParser) { + continue + } + + expect(extractions).toContain(c) + } + }) + }) + + describe('arbitrary properties', () => { + let classes = [ + // With simple arbitrary property + '[display:flex]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('arbitrary values with quotes', () => { + test('arbitrary values with single quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['hello_world']`) + expect(extractions).toContain(`hover:content-['hello_world_2']`) + expect(extractions).toContain(`hover:focus:content-['hello_world_3']`) + }) + + test('arbitrary values with double quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-["hello_world"]`) + expect(extractions).toContain(`hover:content-["hello_world_2"]`) + expect(extractions).toContain(`hover:focus:content-["hello_world_3"]`) + }) + + test('arbitrary values with some single quoted values', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`font-['Open_Sans',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-['Proxima_Nova',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-['Inter_var',_system-ui,_sans-serif]`) + }) + + test('arbitrary values with some double quoted values', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`font-["Open_Sans",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-["Proxima_Nova",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-["Inter_var",_system-ui,_sans-serif]`) + }) + + test('arbitrary values with escaped underscores', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['hello\\_world']`) + expect(extractions).toContain(`hover:content-['hello\\_world\\_2']`) + expect(extractions).toContain(`hover:focus:content-['hello\\_world\\_3']`) + }) + + test('arbitrary values with angle brackets in single quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['>']`) + expect(extractions).toContain(`hover:content-['<']`) + expect(extractions).toContain(`hover:focus:content-['>']`) + }) + + test('arbitrary values with angle brackets in double quotes', async () => { + let extractions = parse(` +
"] hover:content-["<"] hover:focus:content-[">"]">
+ `) + + expect(extractions).toContain(`content-[">"]`) + expect(extractions).toContain(`hover:content-["<"]`) + expect(extractions).toContain(`hover:focus:content-[">"]`) + }) + + test('arbitrary values with theme lookup using quotes', () => { + let extractions = parse(` +

+ `) + + expect(extractions).toContain(`[--y:theme('colors.blue.500')]`) + expect(extractions).toContain(`[color:var(--y)]`) + }) + }) + + test('special characters', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`:font-bold`) + }) + + test('with single quotes array within template literal', async () => { + let extractions = parse(`
`) + + expect(extractions).toContain('pr-1.5') + }) + + test('with double quotes array within template literal', async () => { + let extractions = parse(`
`) + + expect(extractions).toContain('pr-1.5') + }) + + test('with single quotes array within function', async () => { + let extractions = parse(`document.body.classList.add(['pl-1.5'].join(" "));`) + + expect(extractions).toContain('pl-1.5') + }) + + test('with double quotes array within function', async () => { + let extractions = parse(`document.body.classList.add(["pl-1.5"].join(" "));`) + + expect(extractions).toContain('pl-1.5') + }) + + test('with angle brackets', async () => { + let extractions = parse( + `
test
` + ) + + expect(extractions).toContain('bg-blue-200') + expect(extractions).toContain('shadow-xl') + expect(extractions).not.toContain('>shadow-xl') + expect(extractions).not.toContain('shadow-xl<') + }) + + test('markdown code fences', async () => { + let extractions = parse('') + + expect(extractions).toContain('font-bold') + expect(extractions).toContain('font-normal') + expect(extractions).not.toContain('.font-bold') + expect(extractions).not.toContain('.font-normal') + }) + + test('classes in slim templates', async () => { + let extractions = parse(` + p.bg-red-500.text-sm + 'This is a paragraph + small.italic.text-gray-500 + '(Look mom, no closing tag!) + `) + + expect(extractions).toContain('bg-red-500') + expect(extractions).toContain('text-sm') + expect(extractions).toContain('italic') + expect(extractions).toContain('text-gray-500') + }) + + test('multi-word + arbitrary values + quotes', async () => { + let extractions = parse(` + grid-cols-['repeat(2)'] + `) + + expect(extractions).toContain(`grid-cols-['repeat(2)']`) + }) + + test('a lot of data', () => { + let extractions = parse('underline '.repeat(2 ** 17)) + + expect(extractions).toContain(`underline`) + }) + + test('ruby percent string array', () => { + let extractions = parse('%w[text-[#bada55]]') + + expect(extractions).toContain(`text-[#bada55]`) + }) + + test('arbitrary properties followed by square bracketed stuff', () => { + let extractions = parse( + '
[foo]
' + ) + + expect(extractions).toContain(`[display:inherit]`) + }) + + describe('Vue', () => { + test('Class object syntax', () => { + let extractions = parse( + `[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`) + }) + + test('Class array syntax', () => { + // With leading space + let extractions = parse( + `
[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`, `flex`, `block`) + + // Without leading space + extractions = parse( + `
[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`, `flex`, `block`) + }) + }) + + describe('anti-test', () => { + it('should not parse candidates without spaces in object-like syntax', () => { + let extractions = parse(html`
`) + + // The oxide parser _does_ allow this! + if (parse !== oxideParser) { + expect(extractions).not.toContain(`underline:isActive`) + expect(extractions).not.toContain(`flex:isOnline`) + expect(extractions).not.toContain(`md:bold`) + } + + expect(extractions).not.toContain(`underline`) + expect(extractions).not.toContain(`isActive`) + expect(extractions).not.toContain(`flex`) + expect(extractions).not.toContain(`isOnline`) + expect(extractions).not.toContain(`md`) + expect(extractions).not.toContain(`bold`) + }) + }) +}) diff --git a/tests/parseAnimationValue.test.js b/tests/parseAnimationValue.test.js index 098178079..293d6fbec 100644 --- a/tests/parseAnimationValue.test.js +++ b/tests/parseAnimationValue.test.js @@ -1,203 +1,200 @@ import parseAnimationValue from '../src/util/parseAnimationValue' -import { crosscheck } from './util/run' -crosscheck(() => { - describe('Tailwind Defaults', () => { - it.each([ - [ - 'spin 1s linear infinite', - { - value: 'spin 1s linear infinite', - name: 'spin', - duration: '1s', - timingFunction: 'linear', - iterationCount: 'infinite', - }, - ], - [ - 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - { - value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - name: 'ping', - duration: '1s', - timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', - iterationCount: 'infinite', - }, - ], - [ - 'bounce 1s infinite', - { - value: 'bounce 1s infinite', - name: 'bounce', - duration: '1s', - iterationCount: 'infinite', - }, - ], - ])('should be possible to parse: "%s"', (input, expected) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0]).toEqual(expected) - }) - }) - - describe('css variables', () => { - it('should be possible to use css variables', () => { - let parsed = parseAnimationValue('jump var(--animation-duration, 10s) linear infinite') - expect(parsed[0]).toEqual({ - value: 'jump var(--animation-duration, 10s) linear infinite', - name: 'jump', +describe('Tailwind Defaults', () => { + it.each([ + [ + 'spin 1s linear infinite', + { + value: 'spin 1s linear infinite', + name: 'spin', + duration: '1s', timingFunction: 'linear', iterationCount: 'infinite', - unknown: ['var(--animation-duration, 10s)'], - }) - }) - }) - - describe('MDN Examples', () => { - it.each([ - [ - '3s ease-in 1s 2 reverse both paused slidein', - { - value: '3s ease-in 1s 2 reverse both paused slidein', - delay: '1s', - direction: 'reverse', - duration: '3s', - fillMode: 'both', - iterationCount: '2', - name: 'slidein', - playState: 'paused', - timingFunction: 'ease-in', - }, - ], - [ - 'slidein 3s linear 1s', - { - value: 'slidein 3s linear 1s', - delay: '1s', - duration: '3s', - name: 'slidein', - timingFunction: 'linear', - }, - ], - ['slidein 3s', { value: 'slidein 3s', duration: '3s', name: 'slidein' }], - ])('should be possible to parse: "%s"', (input, expected) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0]).toEqual(expected) - }) - }) - - describe('duration & delay', () => { - it.each([ - // Positive seconds (integer) - ['spin 2s 1s linear', { duration: '2s', delay: '1s' }], - - // Negative seconds (integer) - ['spin -2s -1s linear', { duration: '-2s', delay: '-1s' }], - - // Positive seconds (float) - ['spin 2.321s 1.321s linear', { duration: '2.321s', delay: '1.321s' }], - - // Negative seconds (float) - ['spin -2.321s -1.321s linear', { duration: '-2.321s', delay: '-1.321s' }], - - // Positive milliseconds (integer) - ['spin 200ms 100ms linear', { duration: '200ms', delay: '100ms' }], - - // Negative milliseconds (integer) - ['spin -200ms -100ms linear', { duration: '-200ms', delay: '-100ms' }], - - // Positive milliseconds (float) - ['spin 200.321ms 100.321ms linear', { duration: '200.321ms', delay: '100.321ms' }], - - // Negative milliseconds (float) - ['spin -200.321ms -100.321ms linear', { duration: '-200.321ms', delay: '-100.321ms' }], - ])('should be possible to parse "%s" into %o', (input, { duration, delay }) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0].duration).toEqual(duration) - expect(parsed[0].delay).toEqual(delay) - }) - }) - - describe('iteration count', () => { - it.each([ - // Number - ['1 spin 200s 100s linear', '1'], - ['spin 2 200s 100s linear', '2'], - ['spin 200s 3 100s linear', '3'], - ['spin 200s 100s 4 linear', '4'], - ['spin 200s 100s linear 5', '5'], - - // Infinite - ['infinite spin 200s 100s linear', 'infinite'], - ['spin infinite 200s 100s linear', 'infinite'], - ['spin 200s infinite 100s linear', 'infinite'], - ['spin 200s 100s infinite linear', 'infinite'], - ['spin 200s 100s linear infinite', 'infinite'], - ])( - 'should be possible to parse "%s" with an iteraction count of "%s"', - (input, iterationCount) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0].iterationCount).toEqual(iterationCount) - } - ) - }) - - describe('multiple animations', () => { - it('should be possible to parse multiple applications at once', () => { - const input = [ - 'spin 1s linear infinite', - 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', - ].join(',') - - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(3) - expect(parsed).toEqual([ - { - value: 'spin 1s linear infinite', - name: 'spin', - duration: '1s', - timingFunction: 'linear', - iterationCount: 'infinite', - }, - { - value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - name: 'ping', - duration: '1s', - timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', - iterationCount: 'infinite', - }, - { - value: 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', - name: 'pulse', - duration: '2s', - timingFunction: 'cubic-bezier(0.4, 0, 0.6)', - iterationCount: 'infinite', - }, - ]) - }) - }) - - it.each` - input | value | direction | playState | fillMode | iterationCount | timingFunction | duration | delay | name - ${'1s spin 1s infinite'} | ${'1s spin 1s infinite'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'spin'} - ${'infinite infinite 1s 1s'} | ${'infinite infinite 1s 1s'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'infinite'} - ${'ease 1s ease 1s'} | ${'ease 1s ease 1s'} | ${undefined} | ${undefined} | ${undefined} | ${undefined} | ${'ease'} | ${'1s'} | ${'1s'} | ${'ease'} - ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'1s 2s name normal paused backwards infinite ease-in'} | ${'1s 2s name normal paused backwards infinite ease-in'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'2s name normal paused backwards infinite ease-in 1s'} | ${'2s name normal paused backwards infinite ease-in 1s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'2s'} | ${'1s'} | ${'name'} - ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${' name normal paused backwards infinite ease-in 1s 2s '} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - `('should parse "$input" correctly', ({ input, ...expected }) => { - let parsed = parseAnimationValue(input) + }, + ], + [ + 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + { + value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + name: 'ping', + duration: '1s', + timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', + iterationCount: 'infinite', + }, + ], + [ + 'bounce 1s infinite', + { + value: 'bounce 1s infinite', + name: 'bounce', + duration: '1s', + iterationCount: 'infinite', + }, + ], + ])('should be possible to parse: "%s"', (input, expected) => { + const parsed = parseAnimationValue(input) expect(parsed).toHaveLength(1) expect(parsed[0]).toEqual(expected) }) }) + +describe('css variables', () => { + it('should be possible to use css variables', () => { + let parsed = parseAnimationValue('jump var(--animation-duration, 10s) linear infinite') + expect(parsed[0]).toEqual({ + value: 'jump var(--animation-duration, 10s) linear infinite', + name: 'jump', + timingFunction: 'linear', + iterationCount: 'infinite', + unknown: ['var(--animation-duration, 10s)'], + }) + }) +}) + +describe('MDN Examples', () => { + it.each([ + [ + '3s ease-in 1s 2 reverse both paused slidein', + { + value: '3s ease-in 1s 2 reverse both paused slidein', + delay: '1s', + direction: 'reverse', + duration: '3s', + fillMode: 'both', + iterationCount: '2', + name: 'slidein', + playState: 'paused', + timingFunction: 'ease-in', + }, + ], + [ + 'slidein 3s linear 1s', + { + value: 'slidein 3s linear 1s', + delay: '1s', + duration: '3s', + name: 'slidein', + timingFunction: 'linear', + }, + ], + ['slidein 3s', { value: 'slidein 3s', duration: '3s', name: 'slidein' }], + ])('should be possible to parse: "%s"', (input, expected) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0]).toEqual(expected) + }) +}) + +describe('duration & delay', () => { + it.each([ + // Positive seconds (integer) + ['spin 2s 1s linear', { duration: '2s', delay: '1s' }], + + // Negative seconds (integer) + ['spin -2s -1s linear', { duration: '-2s', delay: '-1s' }], + + // Positive seconds (float) + ['spin 2.321s 1.321s linear', { duration: '2.321s', delay: '1.321s' }], + + // Negative seconds (float) + ['spin -2.321s -1.321s linear', { duration: '-2.321s', delay: '-1.321s' }], + + // Positive milliseconds (integer) + ['spin 200ms 100ms linear', { duration: '200ms', delay: '100ms' }], + + // Negative milliseconds (integer) + ['spin -200ms -100ms linear', { duration: '-200ms', delay: '-100ms' }], + + // Positive milliseconds (float) + ['spin 200.321ms 100.321ms linear', { duration: '200.321ms', delay: '100.321ms' }], + + // Negative milliseconds (float) + ['spin -200.321ms -100.321ms linear', { duration: '-200.321ms', delay: '-100.321ms' }], + ])('should be possible to parse "%s" into %o', (input, { duration, delay }) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0].duration).toEqual(duration) + expect(parsed[0].delay).toEqual(delay) + }) +}) + +describe('iteration count', () => { + it.each([ + // Number + ['1 spin 200s 100s linear', '1'], + ['spin 2 200s 100s linear', '2'], + ['spin 200s 3 100s linear', '3'], + ['spin 200s 100s 4 linear', '4'], + ['spin 200s 100s linear 5', '5'], + + // Infinite + ['infinite spin 200s 100s linear', 'infinite'], + ['spin infinite 200s 100s linear', 'infinite'], + ['spin 200s infinite 100s linear', 'infinite'], + ['spin 200s 100s infinite linear', 'infinite'], + ['spin 200s 100s linear infinite', 'infinite'], + ])( + 'should be possible to parse "%s" with an iteraction count of "%s"', + (input, iterationCount) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0].iterationCount).toEqual(iterationCount) + } + ) +}) + +describe('multiple animations', () => { + it('should be possible to parse multiple applications at once', () => { + const input = [ + 'spin 1s linear infinite', + 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', + ].join(',') + + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(3) + expect(parsed).toEqual([ + { + value: 'spin 1s linear infinite', + name: 'spin', + duration: '1s', + timingFunction: 'linear', + iterationCount: 'infinite', + }, + { + value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + name: 'ping', + duration: '1s', + timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', + iterationCount: 'infinite', + }, + { + value: 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', + name: 'pulse', + duration: '2s', + timingFunction: 'cubic-bezier(0.4, 0, 0.6)', + iterationCount: 'infinite', + }, + ]) + }) +}) + +it.each` + input | value | direction | playState | fillMode | iterationCount | timingFunction | duration | delay | name + ${'1s spin 1s infinite'} | ${'1s spin 1s infinite'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'spin'} + ${'infinite infinite 1s 1s'} | ${'infinite infinite 1s 1s'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'infinite'} + ${'ease 1s ease 1s'} | ${'ease 1s ease 1s'} | ${undefined} | ${undefined} | ${undefined} | ${undefined} | ${'ease'} | ${'1s'} | ${'1s'} | ${'ease'} + ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'1s 2s name normal paused backwards infinite ease-in'} | ${'1s 2s name normal paused backwards infinite ease-in'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'2s name normal paused backwards infinite ease-in 1s'} | ${'2s name normal paused backwards infinite ease-in 1s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'2s'} | ${'1s'} | ${'name'} + ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${' name normal paused backwards infinite ease-in 1s 2s '} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} +`('should parse "$input" correctly', ({ input, ...expected }) => { + let parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0]).toEqual(expected) +}) diff --git a/tests/parseObjectStyles.test.js b/tests/parseObjectStyles.test.js index c6121977f..c1a602038 100644 --- a/tests/parseObjectStyles.test.js +++ b/tests/parseObjectStyles.test.js @@ -1,319 +1,317 @@ import parseObjectStyles from '../src/util/parseObjectStyles' import postcss from 'postcss' -import { crosscheck, css } from './util/run' +import { css } from './util/run' function toCss(nodes) { return postcss.root({ nodes }).toString() } -crosscheck(() => { - test('it parses simple single class definitions', () => { - const result = parseObjectStyles({ - '.foobar': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foobar { - color: #fff; - background-color: red; - padding: 1rem; - } - `) +test('it parses simple single class definitions', () => { + let result = parseObjectStyles({ + '.foobar': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + }, }) - test('it parses multiple class definitions', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - }, - '.bar': { - width: '200px', - height: '100px', - }, - }) + expect(toCss(result)).toMatchFormattedCss(css` + .foobar { + background-color: red; + color: white; + padding: 1rem; + } + `) +}) - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .bar { - width: 200px; - height: 100px; - } - `) +test('it parses multiple class definitions', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + }, + '.bar': { + width: '200px', + height: '100px', + }, }) - test('it parses nested pseudo-selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '&:hover': { - backgroundColor: 'orange', - }, - '&:focus': { - backgroundColor: 'blue', - }, - }, - }) + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + .bar { + width: 200px; + height: 100px; + } + `) +}) - expect(toCss(result)).toMatchFormattedCss(css` +test('it parses nested pseudo-selectors', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&:hover': { + backgroundColor: 'orange', + }, + '&:focus': { + backgroundColor: 'blue', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + .foo:hover { + background-color: orange; + } + .foo:focus { + background-color: blue; + } + `) +}) + +test('it parses top-level media queries', () => { + let result = parseObjectStyles({ + '@media (min-width: 200px)': { + '.foo': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + @media (min-width: 200px) { .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .foo:hover { background-color: orange; } - .foo:focus { - background-color: #00f; - } - `) - }) + } + `) +}) - test('it parses top-level media queries', () => { - const result = parseObjectStyles({ +test('it parses nested media queries', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', '@media (min-width: 200px)': { - '.foo': { - backgroundColor: 'orange', - }, + backgroundColor: 'orange', }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - @media (min-width: 200px) { - .foo { - background-color: orange; - } - } - `) + }, }) - test('it parses nested media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + @media (min-width: 200px) { + .foo { + background-color: orange; + } + } + `) +}) + +test('it bubbles nested screen rules', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '@screen sm': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + @screen sm { + .foo { + background-color: orange; + } + } + `) +}) + +test('it parses pseudo-selectors in nested media queries', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&:hover': { '@media (min-width: 200px)': { backgroundColor: 'orange', }, }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo { - background-color: orange; - } - } - `) + }, }) - test('it bubbles nested screen rules', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '@screen sm': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @screen sm { - .foo { - background-color: orange; - } - } - `) - }) - - test('it parses pseudo-selectors in nested media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '&:hover': { - '@media (min-width: 200px)': { - backgroundColor: 'orange', - }, - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo:hover { - background-color: orange; - } - } - `) - }) - - test('it parses descendant selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '.bar': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .foo .bar { + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + @media (min-width: 200px) { + .foo:hover { background-color: orange; } - `) + } + `) +}) + +test('it parses descendant selectors', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '.bar': { + backgroundColor: 'orange', + }, + }, }) - test('it parses nested multi-class selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + .foo .bar { + background-color: orange; + } + `) +}) + +test('it parses nested multi-class selectors', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&.bar': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + .foo.bar { + background-color: orange; + } + `) +}) + +test('it parses nested multi-class selectors in media queries', () => { + let result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '@media (min-width: 200px)': { '&.bar': { backgroundColor: 'orange', }, }, - }) + }, + }) - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: red; + color: white; + padding: 1rem; + } + @media (min-width: 200px) { .foo.bar { background-color: orange; } - `) - }) - - test('it parses nested multi-class selectors in media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '@media (min-width: 200px)': { - '&.bar': { - backgroundColor: 'orange', - }, - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo.bar { - background-color: orange; - } - } - `) - }) - - test('it strips empty selectors when nesting', () => { - const result = parseObjectStyles({ - '.foo': { - '.bar': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo .bar { - background-color: orange; - } - `) - }) - - test('it can parse an array of styles', () => { - const result = parseObjectStyles([ - { - '.foo': { - backgroundColor: 'orange', - }, - }, - { - '.bar': { - backgroundColor: 'red', - }, - }, - { - '.foo': { - backgroundColor: 'blue', - }, - }, - ]) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - background-color: orange; - } - .bar { - background-color: red; - } - .foo { - background-color: #00f; - } - `) - }) - - test('custom properties preserve their case', () => { - const result = parseObjectStyles({ - ':root': { - '--colors-aColor-500': '0', - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - :root { - --colors-aColor-500: 0; - } - `) - }) + } + `) +}) + +test('it strips empty selectors when nesting', () => { + let result = parseObjectStyles({ + '.foo': { + '.bar': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo .bar { + background-color: orange; + } + `) +}) + +test('it can parse an array of styles', () => { + let result = parseObjectStyles([ + { + '.foo': { + backgroundColor: 'orange', + }, + }, + { + '.bar': { + backgroundColor: 'red', + }, + }, + { + '.foo': { + backgroundColor: 'blue', + }, + }, + ]) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: orange; + } + .bar { + background-color: red; + } + .foo { + background-color: blue; + } + `) +}) + +test('custom properties preserve their case', () => { + let result = parseObjectStyles({ + ':root': { + '--colors-aColor-500': '0', + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + :root { + --colors-aColor-500: 0; + } + `) }) diff --git a/tests/plugins/divide.test.js b/tests/plugins/divide.test.js index 314233bea..a5ffa826f 100644 --- a/tests/plugins/divide.test.js +++ b/tests/plugins/divide.test.js @@ -1,102 +1,91 @@ -import { crosscheck, run, html, css, defaults } from '../util/run' +import { run, html, css, defaults } from '../util/run' -crosscheck(({ stable, oxide }) => { - it('should add the divide styles for divide-y and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should add the divide styles for divide-y and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - it('should add the divide styles for divide-x and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - stable.expect(result.css).toMatchCss(css` - ${defaults} - .divide-x > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-right-width: calc(1px * var(--tw-divide-x-reverse)); - border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); - } - `) - - oxide.expect(result.css).toMatchCss(css` - ${defaults} - .divide-x > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(1px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); - } - `) - }) - }) - - it('should add the divide styles for divide-y-reverse and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 1; - } - `) - }) - }) - - it('should add the divide styles for divide-x-reverse and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 1; - } - `) - }) - }) - - it('should only inject the base styles once if we use divide and border at the same time', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - .border-r { - border-right-width: 1px; - } - `) - }) + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +it('should add the divide styles for divide-x and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .divide-x > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 0; + border-right-width: calc(1px * var(--tw-divide-x-reverse)); + border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); + } + `) + }) +}) + +it('should add the divide styles for divide-y-reverse and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .divide-y-reverse > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 1; + } + `) + }) +}) + +it('should add the divide styles for divide-x-reverse and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .divide-x-reverse > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 1; + } + `) + }) +}) + +it('should only inject the base styles once if we use divide and border at the same time', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + .border-r { + border-right-width: 1px; + } + `) }) }) diff --git a/tests/plugins/fontFamily.test.js b/tests/plugins/fontFamily.test.js index 1170dac8e..c0c7aaceb 100644 --- a/tests/plugins/fontFamily.test.js +++ b/tests/plugins/fontFamily.test.js @@ -1,101 +1,99 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(() => { - test('font-family utilities can be defined as a string', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: 'Helvetica, Arial, sans-serif', - }, +test('font-family utilities can be defined as a string', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: 'Helvetica, Arial, sans-serif', }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-family utilities can be defined as an array', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ['Helvetica', 'Arial', 'sans-serif'], - }, +test('font-family utilities can be defined as an array', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ['Helvetica', 'Arial', 'sans-serif'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-family values are not automatically escaped', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ["'Exo 2'", 'sans-serif'], - }, +test('font-family values are not automatically escaped', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ["'Exo 2'", 'sans-serif'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: 'Exo 2', sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: 'Exo 2', sans-serif; + } + `) }) +}) - test('font-feature-settings can be provided when families are defined as a string', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ['Helvetica, Arial, sans-serif', { fontFeatureSettings: '"cv11", "ss01"' }], - }, +test('font-feature-settings can be provided when families are defined as a string', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ['Helvetica, Arial, sans-serif', { fontFeatureSettings: '"cv11", "ss01"' }], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-feature-settings: 'cv11', 'ss01'; - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-feature-settings: 'cv11', 'ss01'; + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-feature-settings can be provided when families are defined as an array', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: [['Helvetica', 'Arial', 'sans-serif'], { fontFeatureSettings: '"cv11", "ss01"' }], - }, +test('font-feature-settings can be provided when families are defined as an array', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: [['Helvetica', 'Arial', 'sans-serif'], { fontFeatureSettings: '"cv11", "ss01"' }], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-feature-settings: 'cv11', 'ss01'; - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-feature-settings: 'cv11', 'ss01'; + font-family: Helvetica, Arial, sans-serif; + } + `) }) }) @@ -110,10 +108,10 @@ test('font-variation-settings can be provided when families are defined as a str } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(` + expect(result.css).toMatchFormattedCss(css` .font-sans { + font-variation-settings: 'opsz' 32; font-family: Inter, sans-serif; - font-variation-settings: "opsz" 32; } `) }) @@ -130,10 +128,10 @@ test('font-variation-settings can be provided when families are defined as an ar } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(` + expect(result.css).toMatchFormattedCss(css` .font-sans { + font-variation-settings: 'opsz' 32; font-family: Inter, sans-serif; - font-variation-settings: "opsz" 32; } `) }) diff --git a/tests/plugins/fontSize.test.js b/tests/plugins/fontSize.test.js index 08e88bb76..99f67eaf6 100644 --- a/tests/plugins/fontSize.test.js +++ b/tests/plugins/fontSize.test.js @@ -1,197 +1,195 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(() => { - test('font-size utilities can include a default line-height', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', '24px'], - lg: ['20px', '28px'], - }, +test('font-size utilities can include a default line-height', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', '24px'], + lg: ['20px', '28px'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - font-size: 20px; - line-height: 28px; - } - .text-md { - font-size: 16px; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a default letter-spacing', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { letterSpacing: '-0.01em' }], - lg: ['20px', { letterSpacing: '-0.02em' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - letter-spacing: -0.02em; - font-size: 20px; - } - .text-md { - letter-spacing: -0.01em; - font-size: 16px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a default line-height and letter-spacing', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { lineHeight: '24px', letterSpacing: '-0.01em' }], - lg: ['20px', { lineHeight: '28px', letterSpacing: '-0.02em' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - letter-spacing: -0.02em; - font-size: 20px; - line-height: 28px; - } - .text-md { - letter-spacing: -0.01em; - font-size: 16px; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a font-weight', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { lineHeight: '24px', fontWeight: 500 }], - lg: ['20px', { lineHeight: '28px', fontWeight: 'bold' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - font-size: 20px; - font-weight: bold; - line-height: 28px; - } - .text-md { - font-size: 16px; - font-weight: 500; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a line-height modifier', () => { - let config = { - content: [ - { - raw: html`
-
-
-
-
-
-
`, - }, - ], - theme: { - fontSize: { - sm: ['12px', '20px'], - base: ['16px', '24px'], - }, - lineHeight: { - 6: '24px', - 7: '28px', - 8: '32px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-\[13px\]\/6 { - font-size: 13px; - line-height: 24px; - } - .text-\[17px\]\/\[23px\] { - font-size: 17px; - line-height: 23px; - } - .text-sm { - font-size: 12px; - line-height: 20px; - } - .text-sm\/6 { - font-size: 12px; - line-height: 24px; - } - .text-sm\/\[21px\] { - font-size: 12px; - line-height: 21px; - } - @media (min-width: 768px) { - .md\:text-\[19px\]\/8 { - font-size: 19px; - line-height: 32px; - } - .md\:text-\[21px\]\/\[29px\] { - font-size: 21px; - line-height: 29px; - } - .md\:text-base { - font-size: 16px; - line-height: 24px; - } - .md\:text-base\/7 { - font-size: 16px; - line-height: 28px; - } - .md\:text-base\/\[33px\] { - font-size: 16px; - line-height: 33px; - } - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-lg { + font-size: 20px; + line-height: 28px; + } + .text-md { + font-size: 16px; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a default letter-spacing', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { letterSpacing: '-0.01em' }], + lg: ['20px', { letterSpacing: '-0.02em' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-lg { + letter-spacing: -0.02em; + font-size: 20px; + } + .text-md { + letter-spacing: -0.01em; + font-size: 16px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a default line-height and letter-spacing', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { lineHeight: '24px', letterSpacing: '-0.01em' }], + lg: ['20px', { lineHeight: '28px', letterSpacing: '-0.02em' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-lg { + letter-spacing: -0.02em; + font-size: 20px; + line-height: 28px; + } + .text-md { + letter-spacing: -0.01em; + font-size: 16px; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a font-weight', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { lineHeight: '24px', fontWeight: 500 }], + lg: ['20px', { lineHeight: '28px', fontWeight: 'bold' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-lg { + font-size: 20px; + font-weight: bold; + line-height: 28px; + } + .text-md { + font-size: 16px; + font-weight: 500; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a line-height modifier', () => { + let config = { + content: [ + { + raw: html`
+
+
+
+
+
+
`, + }, + ], + theme: { + fontSize: { + sm: ['12px', '20px'], + base: ['16px', '24px'], + }, + lineHeight: { + 6: '24px', + 7: '28px', + 8: '32px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-\[13px\]\/6 { + font-size: 13px; + line-height: 24px; + } + .text-\[17px\]\/\[23px\] { + font-size: 17px; + line-height: 23px; + } + .text-sm { + font-size: 12px; + line-height: 20px; + } + .text-sm\/6 { + font-size: 12px; + line-height: 24px; + } + .text-sm\/\[21px\] { + font-size: 12px; + line-height: 21px; + } + @media (min-width: 768px) { + .md\:text-\[19px\]\/8 { + font-size: 19px; + line-height: 32px; + } + .md\:text-\[21px\]\/\[29px\] { + font-size: 21px; + line-height: 29px; + } + .md\:text-base { + font-size: 16px; + line-height: 24px; + } + .md\:text-base\/7 { + font-size: 16px; + line-height: 28px; + } + .md\:text-base\/\[33px\] { + font-size: 16px; + line-height: 33px; + } + } + `) }) }) diff --git a/tests/plugins/gradientColorStops.test.js b/tests/plugins/gradientColorStops.test.js index de79cc8fc..c9647d50f 100644 --- a/tests/plugins/gradientColorStops.test.js +++ b/tests/plugins/gradientColorStops.test.js @@ -1,191 +1,155 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(({ stable, oxide }) => { - test('opacity variables are given to colors defined as closures', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - colors: { - primary: ({ opacityVariable, opacityValue }) => { - if (opacityValue !== undefined) { - return `rgba(31,31,31,${opacityValue})` - } - - if (opacityVariable !== undefined) { - return `rgba(31,31,31,var(${opacityVariable},1))` - } - - return `rgb(31,31,31)` - }, - secondary: 'hsl(10, 50%, 50%)', - }, - opacity: { - 50: '0.5', - }, +test('opacity variables are given to colors defined as closures', () => { + let config = { + content: [ + { + raw: html`
`, }, - } + ], + theme: { + colors: { + primary: ({ opacityVariable, opacityValue }) => { + if (opacityValue !== undefined) { + return `rgba(31,31,31,${opacityValue})` + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .from-primary { - --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-secondary { - --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-primary { - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-secondary { - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .to-primary { - --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); - } - .to-secondary { - --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); - } - .text-primary { - --tw-text-opacity: 1; - color: rgba(31, 31, 31, var(--tw-text-opacity)); - } - .text-secondary { - --tw-text-opacity: 1; - color: hsl(10 50% 50% / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .from-primary { - --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-secondary { - --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-primary { - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-secondary { - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .to-primary { - --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); - } - .to-secondary { - --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); - } - .text-primary { - color: #1f1f1f; - } - .text-secondary { - color: #bf5540; - } - `) - }) - }) + if (opacityVariable !== undefined) { + return `rgba(31,31,31,var(${opacityVariable},1))` + } - test('gradient color stop position', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, + return `rgb(31,31,31)` }, - ], - theme: {}, - } + secondary: 'hsl(10, 50%, 50%)', + }, + opacity: { + 50: '0.5', + }, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .from-\[--from-value\] { - --tw-gradient-from: var(--from-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-red-500 { - --tw-gradient-from: #ef4444 var(--tw-gradient-from-position); - --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-10\% { - --tw-gradient-from-position: 10%; - } - .from-\[11\%\] { - --tw-gradient-from-position: 11%; - } - .from-\[12px\] { - --tw-gradient-from-position: 12px; - } - .via-\[--via-value\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--via-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .via-pink-500 { - --tw-gradient-to: #ec489900 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-20\% { - --tw-gradient-via-position: 20%; - } - .via-\[12\%\] { - --tw-gradient-via-position: 12%; - } - .via-\[123px\] { - --tw-gradient-via-position: 123px; - } - .to-\[--to-value\] { - --tw-gradient-to: var(--to-value) var(--tw-gradient-to-position); - } - .to-violet-400 { - --tw-gradient-to: #a78bfa var(--tw-gradient-to-position); - } - .to-30\% { - --tw-gradient-to-position: 30%; - } - .to-\[13\%\] { - --tw-gradient-to-position: 13%; - } - .to-\[14px\] { - --tw-gradient-to-position: 14px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .from-primary { + --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-secondary { + --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .via-primary { + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .via-secondary { + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .to-primary { + --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); + } + .to-secondary { + --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); + } + .text-primary { + --tw-text-opacity: 1; + color: rgba(31, 31, 31, var(--tw-text-opacity)); + } + .text-secondary { + --tw-text-opacity: 1; + color: hsl(10 50% 50% / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + `) + }) +}) + +test('gradient color stop position', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + theme: {}, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + .from-\[--from-value\] { + --tw-gradient-from: var(--from-value) var(--tw-gradient-from-position); + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-red-500 { + --tw-gradient-from: #ef4444 var(--tw-gradient-from-position); + --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-10\% { + --tw-gradient-from-position: 10%; + } + .from-\[11\%\] { + --tw-gradient-from-position: 11%; + } + .from-\[12px\] { + --tw-gradient-from-position: 12px; + } + .via-\[--via-value\] { + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), + var(--via-value) var(--tw-gradient-via-position), var(--tw-gradient-to); + } + .via-pink-500 { + --tw-gradient-to: #ec489900 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .via-20\% { + --tw-gradient-via-position: 20%; + } + .via-\[12\%\] { + --tw-gradient-via-position: 12%; + } + .via-\[123px\] { + --tw-gradient-via-position: 123px; + } + .to-\[--to-value\] { + --tw-gradient-to: var(--to-value) var(--tw-gradient-to-position); + } + .to-violet-400 { + --tw-gradient-to: #a78bfa var(--tw-gradient-to-position); + } + .to-30\% { + --tw-gradient-to-position: 30%; + } + .to-\[13\%\] { + --tw-gradient-to-position: 13%; + } + .to-\[14px\] { + --tw-gradient-to-position: 14px; + } + `) }) }) diff --git a/tests/postcss-plugins/nesting/index.test.js b/tests/postcss-plugins/nesting/index.test.js index fe942a284..d2c339bf8 100644 --- a/tests/postcss-plugins/nesting/index.test.js +++ b/tests/postcss-plugins/nesting/index.test.js @@ -19,7 +19,7 @@ it('should be possible to load a custom nesting plugin', async () => { rule.selector += '-modified' }) }) - ).toMatchCss(css` + ).toMatchFormattedCss(css` .foo-modified { color: black; @media screen(md) { @@ -39,7 +39,7 @@ it('should be possible to load a custom nesting plugin by name (string) instead' } ` - expect(await run(input, 'postcss-nested')).toMatchCss(css` + expect(await run(input, 'postcss-nested')).toMatchFormattedCss(css` .foo { color: black; } @@ -62,7 +62,7 @@ it('should default to the bundled postcss-nested plugin (no options)', async () } ` - expect(await run(input)).toMatchCss(css` + expect(await run(input)).toMatchFormattedCss(css` .foo { color: black; } @@ -85,7 +85,7 @@ it('should default to the bundled postcss-nested plugin (empty options)', async } ` - expect(await run(input, {})).toMatchCss(css` + expect(await run(input, {})).toMatchFormattedCss(css` .foo { color: black; } @@ -108,7 +108,7 @@ it('should be possible to use postcss-nested plugin with options', async () => { } ` - expect(await run(input, postcssNested({ noIsPseudoSelector: true }))).toMatchCss(css` + expect(await run(input, postcssNested({ noIsPseudoSelector: true }))).toMatchFormattedCss(css` .foo { color: black; } @@ -131,7 +131,7 @@ test('@screen rules are replaced with media queries', async () => { } ` - expect(await run(input, postcssNested)).toMatchCss(css` + expect(await run(input, postcssNested)).toMatchFormattedCss(css` .foo { color: black; } @@ -154,7 +154,7 @@ test('@screen rules can work with `@apply`', async () => { } ` - expect(await run(input, postcssNested)).toMatchCss(css` + expect(await run(input, postcssNested)).toMatchFormattedCss(css` .foo { @apply bg-black; } @@ -172,7 +172,7 @@ test('nesting does not break downstream plugin visitors', async () => { .foo { color: black; } - @suppoerts (color: blue) { + @supports (color: blue) { .foo { color: blue; } @@ -186,15 +186,16 @@ test('nesting does not break downstream plugin visitors', async () => { let result = await run(input, plugins) - expect(result).toMatchCss(css` + expect(result).toMatchFormattedCss(css` .foo { - color: #000; + color: black; } - @suppoerts (color: blue) { + @supports (color: blue) { .foo { color: blue; } } + /* Comment */ `) expect(spyPlugin.spies.Once).toHaveBeenCalled() diff --git a/tests/prefers-contrast.test.js b/tests/prefers-contrast.test.js index e3b940da8..52420ee1e 100644 --- a/tests/prefers-contrast.test.js +++ b/tests/prefers-contrast.test.js @@ -1,102 +1,71 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - it('should be possible to use contrast-more and contrast-less variants', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +it('should be possible to use contrast-more and contrast-less variants', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - .bg-white { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + } + @media (prefers-contrast: more) { + .contrast-more\:bg-pink-500 { + --tw-bg-opacity: 1; + background-color: rgb(236 72 153 / var(--tw-bg-opacity)); + } + } + @media (prefers-contrast: less) { + .contrast-less\:bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + } + `) + }) +}) + +it('dark mode should appear after the contrast variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-contrast: more) { + .contrast-more\:bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + } + @media (prefers-color-scheme: dark) { + .dark\:bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } - @media (prefers-contrast: more) { - .contrast-more\:bg-pink-500 { - --tw-bg-opacity: 1; - background-color: rgb(236 72 153 / var(--tw-bg-opacity)); - } - } - @media (prefers-contrast: less) { - .contrast-less\:bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - .bg-white { - background-color: #fff; - } - @media (prefers-contrast: more) { - .contrast-more\:bg-pink-500 { - background-color: #ec4899; - } - } - @media (prefers-contrast: less) { - .contrast-less\:bg-black { - background-color: #000; - } - } - `) - }) - }) - - it('dark mode should appear after the contrast variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-contrast: more) { - .contrast-more\:bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - } - @media (prefers-color-scheme: dark) { - .dark\:bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-contrast: more) { - .contrast-more\:bg-black { - background-color: #000; - } - } - @media (prefers-color-scheme: dark) { - .dark\:bg-white { - background-color: #fff; - } - } - `) - }) + } + `) }) }) diff --git a/tests/prefix.test.js b/tests/prefix.test.js index ea3d041ff..c9c0e5f25 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -1,625 +1,609 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('prefix') - stable.test('prefix', () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - animation: { - spin: 'spin 1s linear infinite', - ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - }, - keyframes: { - spin: { to: { transform: 'rotate(360deg)' } }, - }, +test('prefix', () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents({ - '.btn-prefix': { + ], + corePlugins: { preflight: false }, + theme: { + animation: { + spin: 'spin 1s linear infinite', + ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + }, + keyframes: { + spin: { to: { transform: 'rotate(360deg)' } }, + }, + }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents({ + '.btn-prefix': { + button: 'yes', + }, + }) + addComponents( + { + '.btn-no-prefix': { button: 'yes', }, - }) - addComponents( - { - '.btn-no-prefix': { - button: 'yes', - }, - }, - { respectPrefix: false } - ) - addUtilities({ - '.custom-util-prefix': { + }, + { respectPrefix: false } + ) + addUtilities({ + '.custom-util-prefix': { + button: 'no', + }, + }) + addUtilities( + { + '.custom-util-no-prefix': { button: 'no', }, - }) - addUtilities( - { - '.custom-util-no-prefix': { - button: 'no', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply tw-font-bold dark:group-hover:tw-font-normal; - } - } - @tailwind utilities; - @layer utilities { - .custom-utility { - foo: bar; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .tw-container { - width: 100%; - } - @media (min-width: 640px) { - .tw-container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .tw-container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .tw-container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .tw-container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .tw-container { - max-width: 1536px; - } - } - .tw-btn-prefix, - .btn-no-prefix { - button: yes; - } - .custom-component { - font-weight: 700; - } - :is(.tw-dark .tw-group:hover .custom-component) { - font-weight: 400; - } - .tw--ml-4 { - margin-left: -1rem; - } - .tw-animate-ping { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; - } - @keyframes tw-spin { - to { - transform: rotate(360deg); - } - } - .tw-animate-spin { - animation: 1s linear infinite tw-spin; - } - .tw-font-bold { - font-weight: 700; - } - .tw-custom-util-prefix, - .custom-util-no-prefix { - button: no; - } - .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { - text-align: left; - } - :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { - text-align: center; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:hover\:tw-text-center:hover { - text-align: center; - } - } - :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - :is(.tw-dark .dark\:focus\:tw-text-left:focus) { - text-align: left; - } - @media (min-width: 768px) { - .md\:tw--ml-5 { - margin-left: -1.25rem; - } - .md\:hover\:tw--ml-6:hover { - margin-left: -1.5rem; - } - .md\:hover\:tw-text-right:hover { - text-align: right; - } - } - `) - }) - }) - - oxide.test.todo('negative values: marker before prefix') - stable.test('negative values: marker before prefix', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-1 { - top: -0.25rem; - } - `) - }) - - oxide.test.todo('negative values: marker after prefix') - stable.test('negative values: marker after prefix', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw--top-1 { - top: -0.25rem; - } - `) - }) - - oxide.test.todo('negative values: marker before prefix and arbitrary value') - stable.test('negative values: marker before prefix and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-\[1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: marker after prefix and arbitrary value') - stable.test('negative values: marker after prefix and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw--top-\[1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: no marker and arbitrary value') - stable.test('negative values: no marker and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw-top-\[-1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: variant versions') - stable.test('negative values: variant versions', async () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .hover\:-tw-top-1:hover { - top: -0.25rem; - } - .hover\:-tw-top-\[1px\]:hover { - top: -1px; - } - .hover\:tw--top-1:hover { - top: -0.25rem; - } - .hover\:tw--top-\[1px\]:hover, - .hover\:tw-top-\[-1px\]:hover { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: prefix and apply') - stable.test('negative values: prefix and apply', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - - .a { - @apply hover:tw--top-1; - } - .b { - @apply hover:-tw-top-1; - } - .c { - @apply hover:-tw-top-[1px]; - } - .d { - @apply hover:tw--top-[1px]; - } - .e { - @apply hover:tw-top-[-1px]; - } - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .a:hover, - .b:hover { - top: -0.25rem; - } - .c:hover, - .d:hover, - .e:hover { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: prefix in the safelist') - stable.test('negative values: prefix in the safelist', async () => { - let config = { - prefix: 'tw-', - safelist: [{ pattern: /-tw-top-1/g }, { pattern: /tw--top-1/g }], - theme: { - inset: { - 1: '0.25rem', - }, + }, + { respectPrefix: false } + ) }, - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } + ], + } - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-1, - .tw--top-1 { - top: -0.25rem; + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply tw-font-bold dark:group-hover:tw-font-normal; } - `) - }) - - oxide.test.todo('prefix with negative values and variants in the safelist') - stable.test('prefix with negative values and variants in the safelist', async () => { - let config = { - prefix: 'tw-', - safelist: [ - { pattern: /-tw-top-1/, variants: ['hover', 'sm:hover'] }, - { pattern: /tw--top-1/, variants: ['hover', 'sm:hover'] }, - ], - theme: { - inset: { - 1: '0.25rem', - }, - }, - content: [{ raw: html`` }], - corePlugins: { preflight: false }, } + @tailwind utilities; + @layer utilities { + .custom-utility { + foo: bar; + } + } + ` - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .-tw-top-1, - .tw--top-1, - .hover\:-tw-top-1:hover, - .hover\:tw--top-1:hover { - top: -0.25rem; + ${defaults} + .tw-container { + width: 100%; } @media (min-width: 640px) { - .sm\:hover\:-tw-top-1:hover, - .sm\:hover\:tw--top-1:hover { - top: -0.25rem; + .tw-container { + max-width: 640px; } } - `) - }) - - oxide.test.todo('prefix does not detect and generate unnecessary classes') - stable.test('prefix does not detect and generate unnecessary classes', async () => { - let config = { - prefix: 'tw-_', - content: [{ raw: html`-aaa-filter aaaa-table aaaa-hidden` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css``) - }) - - oxide.test.todo('supports prefixed utilities using arbitrary values') - stable.test('supports prefixed utilities using arbitrary values', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`foo` }], - corePlugins: { preflight: false }, - } - - let input = css` - .foo { - @apply tw-text-[color:rgb(var(--button-background,var(--primary-button-background)))]; - @apply tw-ease-[cubic-bezier(0.77,0,0.175,1)]; - @apply tw-rounded-[min(4px,var(--input-border-radius))]; - } - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .foo { - color: rgb(var(--button-background, var(--primary-button-background))); - border-radius: min(4px, var(--input-border-radius)); - transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1); - } - `) - }) - - oxide.test.todo('supports non-word prefixes (1)') - stable.test('supports non-word prefixes (1)', async () => { - let config = { - prefix: '@', - content: [ - { - raw: html` -
-
-
-
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-utility { - color: orange; + @media (min-width: 768px) { + .tw-container { + max-width: 768px; } } - .foo { - @apply @text-white; - @apply [background-color:red]; + @media (min-width: 1024px) { + .tw-container { + max-width: 1024px; + } } - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .\@bg-black { + @media (min-width: 1280px) { + .tw-container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .tw-container { + max-width: 1536px; + } + } + .tw-btn-prefix, + .btn-no-prefix { + button: yes; + } + .custom-component { + font-weight: 700; + } + :is(.tw-dark .tw-group:hover .custom-component) { + font-weight: 400; + } + .tw--ml-4 { + margin-left: -1rem; + } + .tw-animate-ping { + animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; + } + @keyframes tw-spin { + to { + transform: rotate(360deg); + } + } + .tw-animate-spin { + animation: 1s linear infinite tw-spin; + } + .tw-font-bold { + font-weight: 700; + } + .tw-custom-util-prefix, + .custom-util-no-prefix { + button: no; + } + .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { + text-align: left; + } + :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:hover\:tw-text-center:hover { + text-align: center; + } + } + :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); } - .\@underline { - text-decoration-line: underline; + :is(.tw-dark .dark\:focus\:tw-text-left:focus) { + text-align: left; } - .my-utility { - color: orange; - } - .foo { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - background-color: red; - } - .hover\:before\:\@content-\[\'Hovering\'\]:hover:before { - --tw-content: 'Hovering'; - content: var(--tw-content); - } - `) - }) - - oxide.test.todo('supports non-word prefixes (2)') - stable.test('supports non-word prefixes (2)', async () => { - let config = { - prefix: '@]$', - content: [ - { - raw: html` -
-
-
-
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-utility { - color: orange; + @media (min-width: 768px) { + .md\:tw--ml-5 { + margin-left: -1.25rem; + } + .md\:hover\:tw--ml-6:hover { + margin-left: -1.5rem; + } + .md\:hover\:tw-text-right:hover { + text-align: right; } - } - .foo { - @apply @]$text-white; - @apply [background-color:red]; - } - ` - - const result = await run(input, config) - - // TODO: The class `.hover\:before\:\@\]\$content-\[\'Hovering\'\]:hover::before` is not generated - // This happens because of the parenthesis/brace/bracket clipping performed on candidates - - expect(result.css).toMatchFormattedCss(css` - .\@\]\$bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .\@\]\$underline { - text-decoration-line: underline; - } - .my-utility { - color: orange; - } - .foo { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - background-color: red; } `) }) }) + +test('negative values: marker before prefix', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1 { + top: -0.25rem; + } + `) +}) + +test('negative values: marker after prefix', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw--top-1 { + top: -0.25rem; + } + `) +}) + +test('negative values: marker before prefix and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-\[1px\] { + top: -1px; + } + `) +}) + +test('negative values: marker after prefix and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw--top-\[1px\] { + top: -1px; + } + `) +}) + +test('negative values: no marker and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw-top-\[-1px\] { + top: -1px; + } + `) +}) + +test('negative values: variant versions', async () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .hover\:-tw-top-1:hover { + top: -0.25rem; + } + .hover\:-tw-top-\[1px\]:hover { + top: -1px; + } + .hover\:tw--top-1:hover { + top: -0.25rem; + } + .hover\:tw--top-\[1px\]:hover, + .hover\:tw-top-\[-1px\]:hover { + top: -1px; + } + `) +}) + +test('negative values: prefix and apply', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + .a { + @apply hover:tw--top-1; + } + .b { + @apply hover:-tw-top-1; + } + .c { + @apply hover:-tw-top-[1px]; + } + .d { + @apply hover:tw--top-[1px]; + } + .e { + @apply hover:tw-top-[-1px]; + } + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .a:hover, + .b:hover { + top: -0.25rem; + } + .c:hover, + .d:hover, + .e:hover { + top: -1px; + } + `) +}) + +test('negative values: prefix in the safelist', async () => { + let config = { + prefix: 'tw-', + safelist: [{ pattern: /-tw-top-1/g }, { pattern: /tw--top-1/g }], + theme: { + inset: { + 1: '0.25rem', + }, + }, + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1, + .tw--top-1 { + top: -0.25rem; + } + `) +}) + +test('prefix with negative values and variants in the safelist', async () => { + let config = { + prefix: 'tw-', + safelist: [ + { pattern: /-tw-top-1/, variants: ['hover', 'sm:hover'] }, + { pattern: /tw--top-1/, variants: ['hover', 'sm:hover'] }, + ], + theme: { + inset: { + 1: '0.25rem', + }, + }, + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1, + .tw--top-1, + .hover\:-tw-top-1:hover, + .hover\:tw--top-1:hover { + top: -0.25rem; + } + @media (min-width: 640px) { + .sm\:hover\:-tw-top-1:hover, + .sm\:hover\:tw--top-1:hover { + top: -0.25rem; + } + } + `) +}) + +test('prefix does not detect and generate unnecessary classes', async () => { + let config = { + prefix: 'tw-_', + content: [{ raw: html`-aaa-filter aaaa-table aaaa-hidden` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css``) +}) + +test('supports prefixed utilities using arbitrary values', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`foo` }], + corePlugins: { preflight: false }, + } + + let input = css` + .foo { + @apply tw-text-[color:rgb(var(--button-background,var(--primary-button-background)))]; + @apply tw-ease-[cubic-bezier(0.77,0,0.175,1)]; + @apply tw-rounded-[min(4px,var(--input-border-radius))]; + } + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo { + color: rgb(var(--button-background, var(--primary-button-background))); + border-radius: min(4px, var(--input-border-radius)); + transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1); + } + `) +}) + +test('supports non-word prefixes (1)', async () => { + let config = { + prefix: '@', + content: [ + { + raw: html` +
+
+
+
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-utility { + color: orange; + } + } + .foo { + @apply @text-white; + @apply [background-color:red]; + } + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .\@bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .\@underline { + text-decoration-line: underline; + } + .my-utility { + color: orange; + } + .foo { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + background-color: red; + } + .hover\:before\:\@content-\[\'Hovering\'\]:hover:before { + --tw-content: 'Hovering'; + content: var(--tw-content); + } + `) +}) + +test('supports non-word prefixes (2)', async () => { + let config = { + prefix: '@]$', + content: [ + { + raw: html` +
+
+
+
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-utility { + color: orange; + } + } + .foo { + @apply @]$text-white; + @apply [background-color:red]; + } + ` + + const result = await run(input, config) + + // TODO: The class `.hover\:before\:\@\]\$content-\[\'Hovering\'\]:hover::before` is not generated + // This happens because of the parenthesis/brace/bracket clipping performed on candidates + + expect(result.css).toMatchFormattedCss(css` + .\@\]\$bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .\@\]\$underline { + text-decoration-line: underline; + } + .my-utility { + color: orange; + } + .foo { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + background-color: red; + } + `) +}) diff --git a/tests/prefixSelector.test.js b/tests/prefixSelector.test.js index c7db08d03..92fd6194f 100644 --- a/tests/prefixSelector.test.js +++ b/tests/prefixSelector.test.js @@ -1,20 +1,17 @@ import prefix from '../src/util/prefixSelector' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it prefixes classes with the provided prefix', () => { - expect(prefix('tw-', '.foo')).toEqual('.tw-foo') - }) - - test('it properly prefixes selectors with non-standard characters', () => { - expect(prefix('tw-', '.hello\\:world')).toEqual('.tw-hello\\:world') - expect(prefix('tw-', '.foo\\/bar')).toEqual('.tw-foo\\/bar') - expect(prefix('tw-', '.wew\\.lad')).toEqual('.tw-wew\\.lad') - }) - - test('it prefixes all classes in a selector', () => { - expect(prefix('tw-', '.btn-blue .w-1\\/4 > h1.text-xl + a .bar')).toEqual( - '.tw-btn-blue .tw-w-1\\/4 > h1.tw-text-xl + a .tw-bar' - ) - }) +test('it prefixes classes with the provided prefix', () => { + expect(prefix('tw-', '.foo')).toEqual('.tw-foo') +}) + +test('it properly prefixes selectors with non-standard characters', () => { + expect(prefix('tw-', '.hello\\:world')).toEqual('.tw-hello\\:world') + expect(prefix('tw-', '.foo\\/bar')).toEqual('.tw-foo\\/bar') + expect(prefix('tw-', '.wew\\.lad')).toEqual('.tw-wew\\.lad') +}) + +test('it prefixes all classes in a selector', () => { + expect(prefix('tw-', '.btn-blue .w-1\\/4 > h1.text-xl + a .bar')).toEqual( + '.tw-btn-blue .tw-w-1\\/4 > h1.tw-text-xl + a .tw-bar' + ) }) diff --git a/tests/preflight.test.js b/tests/preflight.test.js index 4f6f722c7..ad654999e 100644 --- a/tests/preflight.test.js +++ b/tests/preflight.test.js @@ -1,25 +1,23 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('preflight has a correct border color fallback', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - borderColor: ({ theme }) => theme('colors'), - }, - plugins: [], - corePlugins: { preflight: true }, - } +it('preflight has a correct border color fallback', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + borderColor: ({ theme }) => theme('colors'), + }, + plugins: [], + corePlugins: { preflight: true }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toContain(`border-color: currentColor;`) - // Lightning CSS optimizes this to just `border-color: 0 solid;` based on the br value. - oxide.expect(result.css).toContain(`border: 0 solid;`) - }) + return run(input, config).then((result) => { + // Lightning CSS optimizes this to just `border-color: 0 solid;` because `currentcolor` is the default user-agent stylesheet value. + // https://drafts.csswg.org/css-backgrounds/#border-color + expect(result.css).toContain(`border: 0 solid;`) }) }) diff --git a/tests/raw-content.oxide.test.css b/tests/raw-content.oxide.test.css deleted file mode 100644 index aa5abd127..000000000 --- a/tests/raw-content.oxide.test.css +++ /dev/null @@ -1,759 +0,0 @@ -.container { - width: 100%; -} -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} -.sr-only { - width: 1px; - height: 1px; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - margin: -1px; - padding: 0; - position: absolute; - overflow: hidden; -} -.pointer-events-none { - pointer-events: none; -} -.invisible { - visibility: hidden; -} -.collapse { - visibility: collapse; -} -.absolute { - position: absolute; -} -.inset-0 { - inset: 0; -} -.inset-x-2 { - left: 0.5rem; - right: 0.5rem; -} -.inset-y-4 { - top: 1rem; - bottom: 1rem; -} -.bottom-12 { - bottom: 3rem; -} -.left-16 { - left: 4rem; -} -.right-8 { - right: 2rem; -} -.top-6 { - top: 1.5rem; -} -.isolate { - isolation: isolate; -} -.isolation-auto { - isolation: auto; -} -.z-30 { - z-index: 30; -} -.order-2 { - order: 2; -} -.order-last { - order: 9999; -} -.col-span-3 { - grid-column: span 3 / span 3; -} -.col-start-1 { - grid-column-start: 1; -} -.col-end-4 { - grid-column-end: 4; -} -.row-span-2 { - grid-row: span 2 / span 2; -} -.row-start-3 { - grid-row-start: 3; -} -.row-end-5 { - grid-row-end: 5; -} -.float-right { - float: right; -} -.clear-left { - clear: left; -} -.m-4 { - margin: 1rem; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.ml-4 { - margin-left: 1rem; -} -.mr-1 { - margin-right: 0.25rem; -} -.mt-0 { - margin-top: 0; -} -.box-border { - box-sizing: border-box; -} -.inline-grid { - display: inline-grid; -} -.hidden { - display: none; -} -.h-16 { - height: 4rem; -} -.max-h-screen { - max-height: 100vh; -} -.min-h-0 { - min-height: 0; -} -.w-12 { - width: 3rem; -} -.min-w-min { - min-width: min-content; -} -.max-w-full { - max-width: 100%; -} -.flex-1 { - flex: 1; -} -.flex-shrink { - flex-shrink: 1; -} -.flex-shrink-0 { - flex-shrink: 0; -} -.flex-grow { - flex-grow: 1; -} -.flex-grow-0 { - flex-grow: 0; -} -.table-fixed { - table-layout: fixed; -} -.caption-top { - caption-side: top; -} -.caption-bottom { - caption-side: bottom; -} -.border-collapse { - border-collapse: collapse; -} -.origin-top-right { - transform-origin: 100% 0; -} -.-translate-x-3 { - --tw-translate-x: -0.75rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-translate-x-4 { - --tw-translate-x: -1rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-5 { - --tw-translate-x: 1.25rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-6 { - --tw-translate-y: 1.5rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-12 { - --tw-skew-x: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-12 { - --tw-skew-y: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-95 { - --tw-scale-x: 0.95; - --tw-scale-y: 0.95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-gpu { - transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.animate-none { - animation: none; -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.animate-spin { - animation: 1s linear infinite spin; -} -.cursor-pointer { - cursor: pointer; -} -.select-none { - user-select: none; -} -.resize-none { - resize: none; -} -.list-inside { - list-style-position: inside; -} -.list-disc { - list-style-type: disc; -} -.appearance-none { - appearance: none; -} -.auto-cols-min { - grid-auto-columns: min-content; -} -.grid-flow-row { - grid-auto-flow: row; -} -.auto-rows-max { - grid-auto-rows: max-content; -} -.grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} -.grid-rows-3 { - grid-template-rows: repeat(3, minmax(0, 1fr)); -} -.flex-row-reverse { - flex-direction: row-reverse; -} -.flex-wrap { - flex-wrap: wrap; -} -.place-content-start { - place-content: start; -} -.place-items-end { - place-items: end; -} -.content-center { - align-content: center; -} -.items-start { - align-items: flex-start; -} -.justify-center { - justify-content: center; -} -.justify-items-end { - justify-items: end; -} -.gap-4 { - gap: 1rem; -} -.gap-x-2 { - column-gap: 0.5rem; -} -.gap-y-3 { - row-gap: 0.75rem; -} -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); -} -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} -.space-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 1; -} -.space-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 1; -} -.divide-x-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(0px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(0px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(2px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(2px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); -} -.divide-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(4px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(4px * var(--tw-divide-y-reverse)); -} -.divide-dotted > :not([hidden]) ~ :not([hidden]) { - border-style: dotted; -} -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - border-color: #e5e7eb; -} -.place-self-center { - place-self: center; -} -.self-end { - align-self: flex-end; -} -.justify-self-start { - justify-self: start; -} -.overflow-hidden { - overflow: hidden; -} -.overscroll-contain { - overscroll-behavior: contain; -} -.scroll-smooth { - scroll-behavior: smooth; -} -.truncate { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -.overflow-ellipsis { - text-overflow: ellipsis; -} -.whitespace-nowrap { - white-space: nowrap; -} -.break-words { - overflow-wrap: break-word; -} -.rounded-md { - border-radius: 0.375rem; -} -.border { - border-width: 1px; -} -.border-2 { - border-width: 2px; -} -.border-solid { - border-style: solid; -} -.border-black { - border-color: #000; -} -.bg-green-500 { - background-color: #22c55e; -} -.bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); -} -.from-red-300 { - --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); - --tw-gradient-to: #fca5a500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-purple-200 { - --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-blue-400 { - --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); -} -.decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.bg-cover { - background-size: cover; -} -.bg-local { - background-attachment: local; -} -.bg-clip-border { - background-clip: border-box; -} -.bg-top { - background-position: top; -} -.bg-no-repeat { - background-repeat: no-repeat; -} -.bg-origin-border { - background-origin: border-box; -} -.bg-origin-padding { - background-origin: padding-box; -} -.bg-origin-content { - background-origin: content-box; -} -.fill-current { - fill: currentColor; -} -.stroke-current { - stroke: currentColor; -} -.stroke-2 { - stroke-width: 2px; -} -.object-cover { - object-fit: cover; -} -.object-bottom { - object-position: bottom; -} -.p-4 { - padding: 1rem; -} -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pl-4 { - padding-left: 1rem; -} -.pr-2 { - padding-right: 0.5rem; -} -.pt-1 { - padding-top: 0.25rem; -} -.text-center { - text-align: center; -} -.align-middle { - vertical-align: middle; -} -.font-sans { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, - Noto Color Emoji; -} -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} -.font-medium { - font-weight: 500; -} -.uppercase { - text-transform: uppercase; -} -.not-italic { - font-style: normal; -} -.ordinal { - --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.diagonal-fractions { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.leading-5 { - line-height: 1.25rem; -} -.leading-relaxed { - line-height: 1.625; -} -.tracking-tight { - letter-spacing: -0.025em; -} -.text-indigo-500 { - color: #6366f1; -} -.underline { - text-decoration-line: underline; -} -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.placeholder-green-300::placeholder { - color: #86efac; -} -.opacity-90 { - opacity: 0.9; -} -.bg-blend-darken { - background-blend-mode: darken; -} -.bg-blend-difference { - background-blend-mode: difference; -} -.mix-blend-multiply { - mix-blend-mode: multiply; -} -.mix-blend-saturation { - mix-blend-mode: saturation; -} -.shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-lg { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-4 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-white { - --tw-ring-color: #fff; -} -.ring-offset-2 { - --tw-ring-offset-width: 2px; -} -.ring-offset-blue-300 { - --tw-ring-offset-color: #93c5fd; -} -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px #00000012) drop-shadow(0 2px 2px #0000000f); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter { - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter-none { - filter: none; -} -.backdrop-blur-lg { - --tw-backdrop-blur: blur(16px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-50 { - --tw-backdrop-brightness: brightness(0.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-0 { - --tw-backdrop-contrast: contrast(0); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale { - --tw-backdrop-grayscale: grayscale(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-90 { - --tw-backdrop-hue-rotate: hue-rotate(90deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert { - --tw-backdrop-invert: invert(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-75 { - --tw-backdrop-opacity: opacity(0.75); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-150 { - --tw-backdrop-saturate: saturate(1.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia { - --tw-backdrop-sepia: sepia(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter { - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter-none { - backdrop-filter: none; -} -.transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.transition-all { - transition-property: all; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-300 { - transition-delay: 0.3s; -} -.duration-200 { - transition-duration: 0.2s; -} -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} diff --git a/tests/raw-content.test.css b/tests/raw-content.test.css index dba9f3194..cc43ad4c4 100644 --- a/tests/raw-content.test.css +++ b/tests/raw-content.test.css @@ -27,11 +27,11 @@ } } .sr-only { - width: 1px; - height: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; + width: 1px; + height: 1px; margin: -1px; padding: 0; position: absolute; @@ -265,6 +265,7 @@ cursor: pointer; } .select-none { + -webkit-user-select: none; user-select: none; } .resize-none { @@ -277,6 +278,7 @@ list-style-type: disc; } .appearance-none { + -webkit-appearance: none; appearance: none; } .auto-cols-min { @@ -701,69 +703,110 @@ } .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-50 { --tw-backdrop-brightness: brightness(0.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-0 { --tw-backdrop-contrast: contrast(0); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale { --tw-backdrop-grayscale: grayscale(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-90 { --tw-backdrop-hue-rotate: hue-rotate(90deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert { --tw-backdrop-invert: invert(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-75 { --tw-backdrop-opacity: opacity(0.75); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-150 { --tw-backdrop-saturate: saturate(1.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia { --tw-backdrop-sepia: sepia(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter-none { + -webkit-backdrop-filter: none; backdrop-filter: none; } .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; + opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } diff --git a/tests/raw-content.test.js b/tests/raw-content.test.js index 417c37485..a55e373fb 100644 --- a/tests/raw-content.test.js +++ b/tests/raw-content.test.js @@ -1,173 +1,164 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('raw content', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +it('raw content', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './raw-content.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './raw-content.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './raw-content.test.css'), 'utf8') + ) }) }) diff --git a/tests/relative-purge-paths.test.js b/tests/relative-purge-paths.test.js index 95fbe7bad..0e7e5feed 100644 --- a/tests/relative-purge-paths.test.js +++ b/tests/relative-purge-paths.test.js @@ -1,24 +1,22 @@ -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(() => { - test('relative purge paths', () => { - let config = { - content: ['./tests/relative-purge-paths.test.html'], - corePlugins: { preflight: false }, - } +test('relative purge paths', () => { + let config = { + content: ['./tests/relative-purge-paths.test.html'], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toIncludeCss(css` - .font-bold { - font-weight: 700; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toIncludeCss(css` + .font-bold { + font-weight: 700; + } + `) }) }) diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 5c7e0738e..18424e712 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -1,774 +1,926 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic utilities', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } +test('basic utilities', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .skew-y-6 { - --tw-skew-y: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-110 { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with pseudo-class variants', async () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .hover\:scale-x-110:hover { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .focus\:rotate-3:focus { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:focus\:skew-y-6:focus:hover { - --tw-skew-y: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with pseudo-element variants', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .before\:scale-x-110:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .after\:rotate-3:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class variants', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:scale-x-110 { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class pseudo-element variants', async () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:before\:scale-x-110:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:after\:rotate-3:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class pseudo-element and pseudo-class variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:hover\:before\:scale-x-110:hover:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:focus\:after\:rotate-3:focus:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with apply', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - - @layer utilities { - .foo { - @apply rotate-3; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } - - .bar { - @apply before:scale-110; + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } - - .baz::before { - @apply rotate-45; + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } + .rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .skew-y-6 { + --tw-skew-y: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-x-110 { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) +test('with pseudo-class variants', async () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .hover\:scale-x-110:hover { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .focus\:rotate-3:focus { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .hover\:focus\:skew-y-6:focus:hover { + --tw-skew-y: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with pseudo-element variants', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .before\:scale-x-110:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .after\:rotate-3:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class variants', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:scale-x-110 { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class pseudo-element variants', async () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:before\:scale-x-110:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:after\:rotate-3:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class pseudo-element and pseudo-class variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:hover\:before\:scale-x-110:hover:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:focus\:after\:rotate-3:focus:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with apply', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + + @layer utilities { + .foo { + @apply rotate-3; + } + } + + .bar { + @apply before:scale-110; + } + + .baz::before { + @apply rotate-45; + } + + .whats ~ .next > span:hover { + @apply skew-x-6; + } + + .media-queries { + @apply md:rotate-45; + } + + .a, + .b, + .c { + @apply skew-y-3; + } + + .a, + .b { + @apply rotate-45; + } + + .a::before, + .b::after { + @apply rotate-90; + } + + .recursive { + @apply foo; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .foo { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .bar:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + --tw-scale-y: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .baz:before { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } .whats ~ .next > span:hover { - @apply skew-x-6; + --tw-skew-x: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .media-queries { - @apply md:rotate-45; + @media (min-width: 768px) { + .media-queries { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } } - .a, .b, .c { - @apply skew-y-3; + --tw-skew-y: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - .a, .b { - @apply rotate-45; + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .a::before, - .b::after { - @apply rotate-90; - } - - .recursive { - @apply foo; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .foo { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .bar:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - --tw-scale-y: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .baz:before { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .whats ~ .next > span:hover { - --tw-skew-x: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - @media (min-width: 768px) { - .media-queries { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - } - .a, - .b, - .c { - --tw-skew-y: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .a, - .b { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .a:before, - .b:after { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .recursive { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('legacy pseudo-element syntax is supported', async () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - - .a:before { - @apply rotate-45; - } - + .a:before, .b:after { - @apply rotate-3; + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .c:first-line { - @apply rotate-1; + .recursive { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } + `) + }) +}) +test('legacy pseudo-element syntax is supported', async () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + + .a:before { + @apply rotate-45; + } + + .b:after { + @apply rotate-3; + } + + .c:first-line { + @apply rotate-1; + } + + .d:first-letter { + @apply rotate-6; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a:before, + .b:after, + .c:first-line, .d:first-letter { - @apply rotate-6; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .a:before, - .b:after, - .c:first-line, - .d:first-letter { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .a:before { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .b:after { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .c:first-line { - --tw-rotate: 1deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .d:first-letter { - --tw-rotate: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) + .a:before { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .b:after { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .c:first-line { + --tw-rotate: 1deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .d:first-letter { + --tw-rotate: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) }) +}) - test('with borders', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['borderWidth', 'borderColor', 'borderOpacity'], - } +test('with borders', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['borderWidth', 'borderColor', 'borderOpacity'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .border { - border-width: 1px; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .border { + border-width: 1px; + } + .border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(239 68 68 / var(--tw-border-opacity)); + } + @media (min-width: 768px) { + .md\:border-2 { + border-width: 2px; } - .border-red-500 { - --tw-border-opacity: 1; - border-color: rgb(239 68 68 / var(--tw-border-opacity)); - } - @media (min-width: 768px) { - .md\:border-2 { - border-width: 2px; - } - } - `) - }) + } + `) }) +}) - test('with shadows', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['boxShadow', 'ringColor', 'ringWidth'], - } +test('with shadows', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['boxShadow', 'ringColor', 'ringWidth'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + ::-webkit-backdrop { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + ::backdrop { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .ring-black\/25 { + --tw-ring-color: #00000040; + } + @media (min-width: 768px) { + .md\:shadow-xl { + --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), + 0 8px 10px -6px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } - .ring-1 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-black\/25 { - --tw-ring-color: #00000040; - } - @media (min-width: 768px) { - .md\:shadow-xl { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - } - `) - }) - }) - - test('when no utilities that need the defaults are used', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - `) - }) - }) - - test('when a utility uses defaults but they do not exist', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['rotate'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('selectors are reduced to the lowest possible specificity', async () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: [], - } - - let input = css` - @defaults test { - --color: black; } - - /* --- */ - - .foo { - @defaults test; - background-color: var(--color); - } - - #app { - @defaults test; - border-color: var(--color); - } - - span#page { - @defaults test; - color: var(--color); - } - - div[data-foo='bar']#other { - @defaults test; - fill: var(--color); - } - - div[data-bar='baz'] { - @defaults test; - stroke: var(--color); - } - - article { - @defaults test; - --article: var(--color); - } - - div[data-foo='bar']#another::before { - @defaults test; - fill: var(--color); - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo, - [id='app'], - [id='page'], - [id='other'], - [data-bar='baz'], - article, - [id='another']:before { - --color: black; - } - .foo { - background-color: var(--color); - } - #app { - border-color: var(--color); - } - span#page { - color: var(--color); - } - div[data-foo='bar']#other { - fill: var(--color); - } - div[data-bar='baz'] { - stroke: var(--color); - } - article { - --article: var(--color); - } - div[data-foo='bar']#another:before { - fill: var(--color); - } - `) - }) - }) - - test('No defaults without @tailwind base', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - // Optimize universal defaults doesn't work well with isolated modules - // We require you to use @tailwind base to inject the defaults - let input = css` - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .scale-150 { - --tw-scale-x: 1.5; - --tw-scale-y: 1.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('no defaults and apply without @tailwind base', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - // Optimize universal defaults doesn't work well with isolated modules - // We require you to use @tailwind base to inject the defaults - let input = css` - @tailwind components; - @tailwind utilities; - - .my-card { - @apply scale-150; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .my-card { - --tw-scale-x: 1.5; - --tw-scale-y: 1.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) + `) + }) +}) + +test('when no utilities that need the defaults are used', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + `) + }) +}) + +test('when a utility uses defaults but they do not exist', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['rotate'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('selectors are reduced to the lowest possible specificity', async () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: [], + } + + let input = css` + @defaults test { + --color: black; + } + + /* --- */ + + .foo { + @defaults test; + background-color: var(--color); + } + + #app { + @defaults test; + border-color: var(--color); + } + + span#page { + @defaults test; + color: var(--color); + } + + div[data-foo='bar']#other { + @defaults test; + fill: var(--color); + } + + div[data-bar='baz'] { + @defaults test; + stroke: var(--color); + } + + article { + @defaults test; + --article: var(--color); + } + + div[data-foo='bar']#another::before { + @defaults test; + fill: var(--color); + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo, + [id='app'], + [id='page'], + [id='other'], + [data-bar='baz'], + article, + [id='another']:before { + --color: black; + } + .foo { + background-color: var(--color); + } + #app { + border-color: var(--color); + } + span#page { + color: var(--color); + } + div[data-foo='bar']#other { + fill: var(--color); + } + div[data-bar='baz'] { + stroke: var(--color); + } + article { + --article: var(--color); + } + div[data-foo='bar']#another:before { + fill: var(--color); + } + `) + }) +}) + +test('No defaults without @tailwind base', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + // Optimize universal defaults doesn't work well with isolated modules + // We require you to use @tailwind base to inject the defaults + let input = css` + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .scale-150 { + --tw-scale-x: 1.5; + --tw-scale-y: 1.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('no defaults and apply without @tailwind base', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + // Optimize universal defaults doesn't work well with isolated modules + // We require you to use @tailwind base to inject the defaults + let input = css` + @tailwind components; + @tailwind utilities; + + .my-card { + @apply scale-150; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .my-card { + --tw-scale-x: 1.5; + --tw-scale-y: 1.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) }) }) diff --git a/tests/resolveConfig.test.js b/tests/resolveConfig.test.js index c99a986de..954c40659 100644 --- a/tests/resolveConfig.test.js +++ b/tests/resolveConfig.test.js @@ -1,1797 +1,1794 @@ import resolveConfig from '../src/util/resolveConfig' import corePluginList from '../src/corePluginList' -import { crosscheck } from './util/run' -crosscheck(() => { - test('prefix key overrides default prefix', () => { - const userConfig = { - prefix: 'tw-', - } +test('prefix key overrides default prefix', () => { + const userConfig = { + prefix: 'tw-', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: 'tw-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: 'tw-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('important key overrides default important', () => { - const userConfig = { - important: true, - } +test('important key overrides default important', () => { + const userConfig = { + important: true, + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: true, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: true, + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('important (selector) key overrides default important', () => { - const userConfig = { - important: '#app', - } +test('important (selector) key overrides default important', () => { + const userConfig = { + important: '#app', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: '#app', - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: '#app', + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('separator key overrides default separator', () => { - const userConfig = { - separator: '__', - } +test('separator key overrides default separator', () => { + const userConfig = { + separator: '__', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: '__', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: '__', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('theme key is merged instead of replaced', () => { - const userConfig = { - theme: { - screens: { - mobile: '400px', - }, +test('theme key is merged instead of replaced', () => { + const userConfig = { + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - 'grey-darker': '#606f7b', - 'grey-dark': '#8795a1', - grey: '#b8c2cc', - 'grey-light': '#dae1e7', - 'grey-lighter': '#f1f5f8', - }, - fonts: { - sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], - serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], - }, - screens: { - sm: '500px', - md: '750px', - lg: '1000px', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + 'grey-darker': '#606f7b', + 'grey-dark': '#8795a1', + grey: '#b8c2cc', + 'grey-light': '#dae1e7', + 'grey-lighter': '#f1f5f8', }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - 'grey-darker': '#606f7b', - 'grey-dark': '#8795a1', - grey: '#b8c2cc', - 'grey-light': '#dae1e7', - 'grey-lighter': '#f1f5f8', - }, - fonts: { - sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], - serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], - }, - screens: { - mobile: '400px', - }, + fonts: { + sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], + serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], }, - }) + screens: { + sm: '500px', + md: '750px', + lg: '1000px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + 'grey-darker': '#606f7b', + 'grey-dark': '#8795a1', + grey: '#b8c2cc', + 'grey-light': '#dae1e7', + 'grey-lighter': '#f1f5f8', + }, + fonts: { + sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], + serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], + }, + screens: { + mobile: '400px', + }, + }, }) +}) - test('theme key is deeply merged instead of replaced', () => { - const userConfig = { - theme: { - extend: { - colors: { - grey: { - darker: '#606f7b', - dark: '#8795a1', - }, - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - grey: { - grey: '#b8c2cc', - light: '#dae1e7', - lighter: '#f1f5f8', - }, - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { +test('theme key is deeply merged instead of replaced', () => { + const userConfig = { + theme: { + extend: { colors: { grey: { darker: '#606f7b', dark: '#8795a1', - grey: '#b8c2cc', - light: '#dae1e7', - lighter: '#f1f5f8', }, }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + grey: { + grey: '#b8c2cc', + light: '#dae1e7', + lighter: '#f1f5f8', + }, + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + grey: { + darker: '#606f7b', + dark: '#8795a1', + grey: '#b8c2cc', + light: '#dae1e7', + lighter: '#f1f5f8', + }, + }, + }, }) +}) - test('missing top level keys are pulled from the default config', () => { - const userConfig = {} +test('missing top level keys are pulled from the default config', () => { + const userConfig = {} - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { green: '#00ff00' }, - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { green: '#00ff00' }, + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { green: '#00ff00' }, - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { green: '#00ff00' }, + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('functions in the default theme section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, +test('functions in the default theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: (theme) => theme('colors'), - textColors: (theme) => theme('colors'), + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - } + backgroundColors: (theme) => theme('colors'), + textColors: (theme) => theme('colors'), + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - textColors: { - red: 'red', - green: 'green', - blue: 'blue', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - }) + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, }) +}) - test('functions in the user theme section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: (theme) => ({ - ...theme('colors'), - customBackground: '#bada55', - }), - textColors: (theme) => ({ - ...theme('colors'), - customText: '#facade', - }), +test('functions in the user theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + backgroundColors: (theme) => ({ + ...theme('colors'), + customBackground: '#bada55', + }), + textColors: (theme) => ({ + ...theme('colors'), + customText: '#facade', + }), + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: ({ colors }) => colors, - textColors: ({ colors }) => colors, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - } + backgroundColors: ({ colors }) => colors, + textColors: ({ colors }) => colors, + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - red: 'red', - green: 'green', - blue: 'blue', - customBackground: '#bada55', - }, - textColors: { - red: 'red', - green: 'green', - blue: 'blue', - customText: '#facade', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - }) + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + customBackground: '#bada55', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + customText: '#facade', + }, + }, }) +}) - test('theme values in the extend section extend the existing theme', () => { - const userConfig = { - theme: { - extend: { - opacity: { - 25: '25', - 75: '.75', - }, - backgroundColors: { - customBackground: '#bada55', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, +test('theme values in the extend section extend the existing theme', () => { + const userConfig = { + theme: { + extend: { opacity: { - 0: '0', - 50: '.5', - 100: '1', - }, - backgroundColors: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - opacity: { - 0: '0', - 50: '.5', - 100: '1', 25: '25', 75: '.75', }, backgroundColors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', customBackground: '#bada55', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + opacity: { + 0: '0', + 50: '.5', + 100: '1', + }, + backgroundColors: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + opacity: { + 0: '0', + 50: '.5', + 100: '1', + 25: '25', + 75: '.75', + }, + backgroundColors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + customBackground: '#bada55', + }, + }, }) +}) - test('theme values in the extend section extend the user theme', () => { - const userConfig = { - theme: { - opacity: { - 0: '0', - 20: '.2', - 40: '.4', - }, - height: (theme) => theme('width'), - extend: { - opacity: { - 60: '.6', - 80: '.8', - 100: '1', - }, - height: { - customHeight: '500vh', - }, - }, +test('theme values in the extend section extend the user theme', () => { + const userConfig = { + theme: { + opacity: { + 0: '0', + 20: '.2', + 40: '.4', }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + height: (theme) => theme('width'), + extend: { opacity: { - 0: '0', - 50: '.5', - 100: '1', - }, - height: { - 0: 0, - full: '100%', - }, - width: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - opacity: { - 0: '0', - 20: '.2', - 40: '.4', 60: '.6', 80: '.8', 100: '1', }, height: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', customHeight: '500vh', }, - width: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', - }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + opacity: { + 0: '0', + 50: '.5', + 100: '1', + }, + height: { + 0: 0, + full: '100%', + }, + width: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + opacity: { + 0: '0', + 20: '.2', + 40: '.4', + 60: '.6', + 80: '.8', + 100: '1', + }, + height: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + customHeight: '500vh', + }, + width: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + }, + }, }) +}) - test('theme values in the extend section can extend values that are depended on lazily', () => { - const userConfig = { - theme: { - extend: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - customBackground: '#bada55', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { +test('theme values in the extend section can extend values that are depended on lazily', () => { + const userConfig = { + theme: { + extend: { colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', red: 'red', green: 'green', blue: 'blue', }, backgroundColors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - red: 'red', - green: 'green', - blue: 'blue', customBackground: '#bada55', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + backgroundColors: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + red: 'red', + green: 'green', + blue: 'blue', + customBackground: '#bada55', + }, + }, }) +}) - test('theme values in the extend section are not deeply merged when they are simple arrays', () => { - const userConfig = { - theme: { - extend: { - fonts: { - sans: ['Comic Sans'], - serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], - mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - fonts: { - sans: ['system-ui', 'Helvetica Neue', 'sans-serif'], - serif: ['Constantia', 'Georgia', 'serif'], - mono: ['Menlo', 'Courier New', 'monospace'], - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { +test('theme values in the extend section are not deeply merged when they are simple arrays', () => { + const userConfig = { + theme: { + extend: { fonts: { sans: ['Comic Sans'], serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], }, }, - }) - }) + }, + } - test('theme values in the extend section are deeply merged, when they are arrays of objects', () => { - const userConfig = { - theme: { - extend: { - typography: { - ArrayArray: { - css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], - }, - ObjectArray: { - css: { a: { backgroundColor: 'red' } }, - }, - ArrayObject: { - css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], - }, - }, - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + fonts: { + sans: ['system-ui', 'Helvetica Neue', 'sans-serif'], + serif: ['Constantia', 'Georgia', 'serif'], + mono: ['Menlo', 'Courier New', 'monospace'], }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + fonts: { + sans: ['Comic Sans'], + serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], + mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], + }, + }, + }) +}) + +test('theme values in the extend section are deeply merged, when they are arrays of objects', () => { + const userConfig = { + theme: { + extend: { typography: { ArrayArray: { - css: [{ a: { underline: 'none' } }], + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], }, ObjectArray: { - css: [{ a: { underline: 'none' } }], + css: { a: { backgroundColor: 'red' } }, }, ArrayObject: { - css: { a: { underline: 'none' } }, + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], }, }, }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - typography: { - ArrayArray: { - css: [ - { a: { underline: 'none' } }, - { a: { backgroundColor: 'red' } }, - { a: { color: 'green' } }, - ], - }, - ObjectArray: { - css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }], - }, - ArrayObject: { - css: [ - { a: { underline: 'none' } }, - { a: { backgroundColor: 'red' } }, - { a: { color: 'green' } }, - ], - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + typography: { + ArrayArray: { + css: [{ a: { underline: 'none' } }], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }], + }, + ArrayObject: { + css: { a: { underline: 'none' } }, }, }, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + typography: { + ArrayArray: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }], + }, + ArrayObject: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + }, + }, }) +}) - test('the theme function can use a default value if the key is missing', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, +test('the theme function can use a default value if the key is missing', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + borderColor: (theme) => ({ + default: theme('colors.gray', 'currentColor'), + ...theme('colors'), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + default: 'currentColor', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + }) +}) + +test('the theme function can resolve function values', () => { + const userConfig = { + theme: { + textColor: (theme) => ({ + lime: 'lime', + ...theme('colors'), + }), + backgroundColor: (theme) => ({ + orange: 'orange', + ...theme('textColor'), + }), + borderColor: (theme) => theme('backgroundColor'), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + textColor: { + lime: 'lime', + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColor: { + lime: 'lime', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + lime: 'lime', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + }) +}) + +test('the theme function can resolve deep function values', () => { + const userConfig = { + theme: { + minWidth: (theme) => ({ + '1/3': theme('width.1/3'), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + spacing: { + 0: '0', + }, + width: (theme) => ({ + ...theme('spacing'), + '1/3': '33.33333%', + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + spacing: { + 0: '0', + }, + width: { + 0: '0', + '1/3': '33.33333%', + }, + minWidth: { + '1/3': '33.33333%', + }, + }, + }) +}) + +test('theme values in the extend section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + extend: { colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', + orange: 'orange', }, borderColor: (theme) => ({ - default: theme('colors.gray', 'currentColor'), - ...theme('colors'), + foo: theme('colors.orange'), + bar: theme('colors.red'), }), }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - default: 'currentColor', - red: 'red', - green: 'green', - blue: 'blue', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - }) + borderColor: (theme) => ({ + default: theme('colors.yellow', 'currentColor'), + ...theme('colors'), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + default: 'currentColor', + foo: 'orange', + bar: 'red', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, }) +}) - test('the theme function can resolve function values', () => { - const userConfig = { - theme: { - textColor: (theme) => ({ - lime: 'lime', - ...theme('colors'), +test('lazily evaluated values have access to the config utils', () => { + const userConfig = { + theme: { + inset: (theme) => theme('margin'), + shift: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + extend: { + nudge: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), }), - backgroundColor: (theme) => ({ + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + spacing: { + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + margin: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + spacing: { + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + inset: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + margin: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + shift: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + nudge: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + }, + }) +}) + +test('the original theme is not mutated', () => { + const userConfig = { + theme: { + extend: { + colors: { orange: 'orange', - ...theme('textColor'), + }, + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + }, + } + + resolveConfig([userConfig, defaultConfig]) + + expect(userConfig).toEqual({ + theme: { + extend: { + colors: { + orange: 'orange', + }, + }, + }, + }) +}) + +test('custom properties are multiplied by -1 for negative values', () => { + const userConfig = { + theme: { + spacing: { + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + }, + margin: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: {}, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result.theme.spacing).toEqual({ + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + }) + expect(result.theme.margin).toEqual({ + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + '-0': '0', + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + '-foo': 'calc(var(--foo) * -1)', + '-bar': 'calc(var(--bar, 500px) * -1)', + '-baz': 'calc(calc(50% - 10px) * -1)', + '-qux': '-10poops', + }) +}) + +test('more than two config objects can be resolved', () => { + const firstConfig = { + theme: { + extend: { + fontFamily: () => ({ + code: ['Menlo', 'monospace'], }), - borderColor: (theme) => theme('backgroundColor'), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { colors: { red: 'red', - green: 'green', - blue: 'blue', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - textColor: { - lime: 'lime', - red: 'red', - green: 'green', - blue: 'blue', }, backgroundColor: { - lime: 'lime', + customBackgroundOne: '#bada55', + }, + textDecorationColor: { orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - lime: 'lime', - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', }, }, - }) - }) + }, + } - test('the theme function can resolve deep function values', () => { - const userConfig = { - theme: { - minWidth: (theme) => ({ - '1/3': theme('width.1/3'), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - spacing: { - 0: '0', - }, - width: (theme) => ({ - ...theme('spacing'), - '1/3': '33.33333%', - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - spacing: { - 0: '0', - }, - width: { - 0: '0', - '1/3': '33.33333%', - }, - minWidth: { - '1/3': '33.33333%', - }, - }, - }) - }) - - test('theme values in the extend section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - extend: { - colors: { - orange: 'orange', - }, - borderColor: (theme) => ({ - foo: theme('colors.orange'), - bar: theme('colors.red'), - }), - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - borderColor: (theme) => ({ - default: theme('colors.yellow', 'currentColor'), - ...theme('colors'), - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - default: 'currentColor', - foo: 'orange', - bar: 'red', - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - }, - }) - }) - - test('lazily evaluated values have access to the config utils', () => { - const userConfig = { - theme: { - inset: (theme) => theme('margin'), - shift: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - extend: { - nudge: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - spacing: { - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - margin: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - spacing: { - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - inset: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - margin: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - shift: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - nudge: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - }, - }) - }) - - test('the original theme is not mutated', () => { - const userConfig = { - theme: { - extend: { - colors: { - orange: 'orange', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - }, - } - - resolveConfig([userConfig, defaultConfig]) - - expect(userConfig).toEqual({ - theme: { - extend: { - colors: { - orange: 'orange', - }, - }, - }, - }) - }) - - test('custom properties are multiplied by -1 for negative values', () => { - const userConfig = { - theme: { - spacing: { - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - }, - margin: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: {}, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result.theme.spacing).toEqual({ - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - }) - expect(result.theme.margin).toEqual({ - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - '-0': '0', - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - '-foo': 'calc(var(--foo) * -1)', - '-bar': 'calc(var(--bar, 500px) * -1)', - '-baz': 'calc(calc(50% - 10px) * -1)', - '-qux': '-10poops', - }) - }) - - test('more than two config objects can be resolved', () => { - const firstConfig = { - theme: { - extend: { - fontFamily: () => ({ - code: ['Menlo', 'monospace'], - }), - colors: { - red: 'red', - }, - backgroundColor: { - customBackgroundOne: '#bada55', - }, - textDecorationColor: { - orange: 'orange', - }, - }, - }, - } - - const secondConfig = { - prefix: '-', - important: false, - separator: ':', - theme: { - extend: { - fontFamily: { - quote: ['Helvetica', 'serif'], - }, - colors: { - green: 'green', - }, - backgroundColor: { - customBackgroundTwo: '#facade', - }, - textDecorationColor: (theme) => theme('colors'), - }, - }, - } - - const thirdConfig = { - prefix: '-', - important: false, - separator: ':', - theme: { - extend: { - fontFamily: { - hero: ['Futura', 'sans-serif'], - }, - colors: { - pink: 'pink', - }, - backgroundColor: () => ({ - customBackgroundThree: '#c0ffee', - }), - textDecorationColor: { - lime: 'lime', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const secondConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + extend: { fontFamily: { - body: ['Arial', 'sans-serif'], - display: ['Georgia', 'serif'], - }, - colors: { - blue: 'blue', - }, - backgroundColor: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([firstConfig, secondConfig, thirdConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - fontFamily: { - body: ['Arial', 'sans-serif'], - display: ['Georgia', 'serif'], - code: ['Menlo', 'monospace'], quote: ['Helvetica', 'serif'], + }, + colors: { + green: 'green', + }, + backgroundColor: { + customBackgroundTwo: '#facade', + }, + textDecorationColor: (theme) => theme('colors'), + }, + }, + } + + const thirdConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + extend: { + fontFamily: { hero: ['Futura', 'sans-serif'], }, colors: { - red: 'red', - green: 'green', - blue: 'blue', pink: 'pink', }, - backgroundColor: { - red: 'red', - green: 'green', - blue: 'blue', - pink: 'pink', - customBackgroundOne: '#bada55', - customBackgroundTwo: '#facade', + backgroundColor: () => ({ customBackgroundThree: '#c0ffee', - }, + }), textDecorationColor: { - red: 'red', - green: 'green', - blue: 'blue', - pink: 'pink', - orange: 'orange', lime: 'lime', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + fontFamily: { + body: ['Arial', 'sans-serif'], + display: ['Georgia', 'serif'], + }, + colors: { + blue: 'blue', + }, + backgroundColor: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([firstConfig, secondConfig, thirdConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + fontFamily: { + body: ['Arial', 'sans-serif'], + display: ['Georgia', 'serif'], + code: ['Menlo', 'monospace'], + quote: ['Helvetica', 'serif'], + hero: ['Futura', 'sans-serif'], + }, + colors: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + }, + backgroundColor: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + customBackgroundOne: '#bada55', + customBackgroundTwo: '#facade', + customBackgroundThree: '#c0ffee', + }, + textDecorationColor: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + orange: 'orange', + lime: 'lime', + }, + }, }) +}) - test('plugin config modifications are applied', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', +test('plugin config modifications are applied', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'tw-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'tw-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('user config takes precedence over plugin config modifications', () => { - const userConfig = { - prefix: 'user-', - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', +test('user config takes precedence over plugin config modifications', () => { + const userConfig = { + prefix: 'user-', + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'user-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'user-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin config can register plugins that also have config', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'tw-', - plugins: [ - { - config: { - important: true, - }, +test('plugin config can register plugins that also have config', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'tw-', + plugins: [ + { + config: { + important: true, }, - { - config: { - separator: '__', - }, + }, + { + config: { + separator: '__', }, - ], - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', + }, + ], }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'tw-', - important: true, - separator: '__', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'tw-', + important: true, + separator: '__', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin configs take precedence over plugin configs registered by that plugin', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'outer-', - plugins: [ - { - config: { - prefix: 'inner-', - }, +test('plugin configs take precedence over plugin configs registered by that plugin', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'outer-', + plugins: [ + { + config: { + prefix: 'inner-', }, - ], - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', + }, + ], }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'outer-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'outer-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin theme extensions are added even if user overrides top-level theme config', () => { - const userConfig = { - theme: { - width: { - '1px': '1px', - }, +test('plugin theme extensions are added even if user overrides top-level theme config', () => { + const userConfig = { + theme: { + width: { + '1px': '1px', }, - plugins: [ - { - config: { - theme: { - extend: { - width: { - '2px': '2px', - '3px': '3px', - }, + }, + plugins: [ + { + config: { + theme: { + extend: { + width: { + '2px': '2px', + '3px': '3px', }, }, }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - width: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - screens: { - mobile: '400px', }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: { - width: { - '1px': '1px', - '2px': '2px', - '3px': '3px', - }, - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', }, - plugins: userConfig.plugins, - }) + screens: { + mobile: '400px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: { + width: { + '1px': '1px', + '2px': '2px', + '3px': '3px', + }, + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('user theme extensions take precedence over plugin theme extensions with the same key', () => { - const userConfig = { - theme: { - extend: { - width: { - xl: '6rem', - }, - }, - }, - plugins: [ - { - config: { - theme: { - extend: { - width: { - xl: '4rem', - }, - }, - }, - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { +test('user theme extensions take precedence over plugin theme extensions with the same key', () => { + const userConfig = { + theme: { + extend: { width: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - screens: { - mobile: '400px', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: { - width: { - sm: '1rem', - md: '2rem', - lg: '3rem', xl: '6rem', }, - screens: { - mobile: '400px', - }, }, - plugins: userConfig.plugins, - }) + }, + plugins: [ + { + config: { + theme: { + extend: { + width: { + xl: '4rem', + }, + }, + }, + }, + handler() {}, + }, + ], + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, + screens: { + mobile: '400px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', + xl: '6rem', + }, + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('extensions are applied in the right order', () => { - const userConfig = { - theme: { - extend: { - colors: { - grey: { - light: '#eee', - }, - }, - }, - }, - } - - const otherConfig = { - theme: { - extend: { - colors: { - grey: { - light: '#ddd', - darker: '#111', - }, - }, - }, - }, - } - - const anotherConfig = { - theme: { - extend: { - colors: { - grey: { - darker: '#222', - }, - }, - }, - }, - } - - const defaultConfig = { - content: [], - theme: { - colors: { - grey: { - light: '#ccc', - dark: '#333', - }, - }, - }, - } - - const result = resolveConfig([userConfig, otherConfig, anotherConfig, defaultConfig]) - - expect(result).toMatchObject({ - theme: { +test('extensions are applied in the right order', () => { + const userConfig = { + theme: { + extend: { colors: { grey: { light: '#eee', - dark: '#333', + }, + }, + }, + }, + } + + const otherConfig = { + theme: { + extend: { + colors: { + grey: { + light: '#ddd', darker: '#111', }, }, }, - }) - }) + }, + } - test('core plugin configuration builds on the default list when starting with an empty object', () => { - const userConfig = { - corePlugins: { display: false }, - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: {}, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - corePlugins: corePluginList.filter((c) => c !== 'display'), - }) - }) - - test('core plugins that are disabled by default can be enabled', () => { - const userConfig = { - corePlugins: { display: true }, - } - - const defaultConfig = { - presets: [], - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: { display: false }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - expect(result.corePlugins).toContain('display') - }) - - test('core plugin configurations stack', () => { - const userConfig = { - corePlugins: { display: false }, - } - - const otherConfig = { - corePlugins: ({ corePlugins }) => { - return [...corePlugins, 'margin'] - }, - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: ['float', 'display', 'padding'], - } - - const result = resolveConfig([userConfig, otherConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - corePlugins: ['float', 'padding', 'margin'], - }) - }) - - test('plugins are merged', () => { - const userConfig = { - plugins: ['3'], - } - - const otherConfig = { - plugins: ['2'], - } - - const defaultConfig = { - plugins: ['1'], - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - } - - const result = resolveConfig([userConfig, otherConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - plugins: ['1', '2', '3'], - }) - }) - - test('all helpers can be destructured from the first function argument', () => { - const userConfig = { - theme: { - example: ({ theme, colors, negative, breakpoints }) => ({ - weight: theme('fontWeight.bold'), - black: colors.black, - white: colors.white, - ...negative(theme('spacing')), - ...breakpoints(theme('screens')), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - screens: { - sm: '640px', - md: '768px', - }, - fontWeight: { - bold: 700, - }, - spacing: { - 0: '0px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - example: { - weight: 700, - black: '#000', - white: '#fff', - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 'screen-sm': '640px', - 'screen-md': '768px', - }, - }, - }) - }) - - test('does not duplicate extended configs every time resolveConfig is called', () => { - let shared = { - foo: { bar: { baz: [{ color: 'red' }] } }, - } - - const createConfig = (color) => - resolveConfig([ - { - theme: { - foo: shared.foo, - extend: { - foo: { bar: { baz: { color } } }, - }, + const anotherConfig = { + theme: { + extend: { + colors: { + grey: { + darker: '#222', }, }, - ]) + }, + }, + } - createConfig('orange') - createConfig('yellow') - createConfig('green') + const defaultConfig = { + content: [], + theme: { + colors: { + grey: { + light: '#ccc', + dark: '#333', + }, + }, + }, + } - const result = createConfig('blue') + const result = resolveConfig([userConfig, otherConfig, anotherConfig, defaultConfig]) - expect(shared.foo.bar.baz).toMatchObject([{ color: 'red' }]) - expect(result.theme.foo.bar.baz).toMatchObject([{ color: 'red' }, { color: 'blue' }]) + expect(result).toMatchObject({ + theme: { + colors: { + grey: { + light: '#eee', + dark: '#333', + darker: '#111', + }, + }, + }, }) }) + +test('core plugin configuration builds on the default list when starting with an empty object', () => { + const userConfig = { + corePlugins: { display: false }, + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: {}, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + corePlugins: corePluginList.filter((c) => c !== 'display'), + }) +}) + +test('core plugins that are disabled by default can be enabled', () => { + const userConfig = { + corePlugins: { display: true }, + } + + const defaultConfig = { + presets: [], + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: { display: false }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + expect(result.corePlugins).toContain('display') +}) + +test('core plugin configurations stack', () => { + const userConfig = { + corePlugins: { display: false }, + } + + const otherConfig = { + corePlugins: ({ corePlugins }) => { + return [...corePlugins, 'margin'] + }, + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: ['float', 'display', 'padding'], + } + + const result = resolveConfig([userConfig, otherConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + corePlugins: ['float', 'padding', 'margin'], + }) +}) + +test('plugins are merged', () => { + const userConfig = { + plugins: ['3'], + } + + const otherConfig = { + plugins: ['2'], + } + + const defaultConfig = { + plugins: ['1'], + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + } + + const result = resolveConfig([userConfig, otherConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + plugins: ['1', '2', '3'], + }) +}) + +test('all helpers can be destructured from the first function argument', () => { + const userConfig = { + theme: { + example: ({ theme, colors, negative, breakpoints }) => ({ + weight: theme('fontWeight.bold'), + black: colors.black, + white: colors.white, + ...negative(theme('spacing')), + ...breakpoints(theme('screens')), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + screens: { + sm: '640px', + md: '768px', + }, + fontWeight: { + bold: 700, + }, + spacing: { + 0: '0px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + example: { + weight: 700, + black: '#000', + white: '#fff', + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 'screen-sm': '640px', + 'screen-md': '768px', + }, + }, + }) +}) + +test('does not duplicate extended configs every time resolveConfig is called', () => { + let shared = { + foo: { bar: { baz: [{ color: 'red' }] } }, + } + + const createConfig = (color) => + resolveConfig([ + { + theme: { + foo: shared.foo, + extend: { + foo: { bar: { baz: { color } } }, + }, + }, + }, + ]) + + createConfig('orange') + createConfig('yellow') + createConfig('green') + + const result = createConfig('blue') + + expect(shared.foo.bar.baz).toMatchObject([{ color: 'red' }]) + expect(result.theme.foo.bar.baz).toMatchObject([{ color: 'red' }, { color: 'blue' }]) +}) diff --git a/tests/responsive-and-variants-atrules.test.js b/tests/responsive-and-variants-atrules.test.js index 9d9ed5d85..4d4a0f507 100644 --- a/tests/responsive-and-variants-atrules.test.js +++ b/tests/responsive-and-variants-atrules.test.js @@ -1,157 +1,155 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('responsive and variants atrules', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +test('responsive and variants atrules', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind components; - @tailwind utilities; - - @layer utilities { - @responsive { - .responsive-in-utilities { - color: blue; - } - } - @variants { - .variants-in-utilities { - color: red; - } - } - @responsive { - @variants { - .both-in-utilities { - color: green; - } - } - } - } + let input = css` + @tailwind components; + @tailwind utilities; + @layer utilities { @responsive { - .responsive-at-root { - color: white; + .responsive-in-utilities { + color: blue; } } @variants { - .variants-at-root { - color: orange; + .variants-in-utilities { + color: red; } } @responsive { @variants { - .both-at-root { - color: pink; + .both-in-utilities { + color: green; } } } + } - @layer components { - @responsive { - .responsive-in-components { - color: blue; - } - } - @variants { - .variants-in-components { - color: red; - } - } - @responsive { - @variants { - .both-in-components { - color: green; - } - } - } + @responsive { + .responsive-at-root { + color: white; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .responsive-in-components { - color: #00f; - } - .variants-in-components { - color: red; - } - .both-in-components { - color: green; - } - .responsive-in-utilities { - color: #00f; - } - .variants-in-utilities { - color: red; - } - .both-in-utilities { - color: green; - } - .responsive-at-root { - color: #fff; - } - .variants-at-root { - color: orange; - } + } + @variants { + .variants-at-root { + color: orange; + } + } + @responsive { + @variants { .both-at-root { color: pink; } - @media (min-width: 768px) { - .md\:focus\:responsive-in-components:focus { - color: #00f; - } - .md\:focus\:variants-in-components:focus { - color: red; - } - .md\:focus\:both-in-components:focus { + } + } + + @layer components { + @responsive { + .responsive-in-components { + color: blue; + } + } + @variants { + .variants-in-components { + color: red; + } + } + @responsive { + @variants { + .both-in-components { color: green; } - .md\:focus\:responsive-in-utilities:focus { - color: #00f; - } - .md\:focus\:variants-in-utilities:focus { - color: red; - } - .md\:focus\:both-in-utilities:focus { - color: green; - } - .md\:focus\:responsive-at-root:focus { - color: #fff; - } - .md\:focus\:variants-at-root:focus { - color: orange; - } - .md\:focus\:both-at-root:focus { - color: pink; - } } - `) - }) + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .responsive-in-components { + color: #00f; + } + .variants-in-components { + color: red; + } + .both-in-components { + color: green; + } + .responsive-in-utilities { + color: #00f; + } + .variants-in-utilities { + color: red; + } + .both-in-utilities { + color: green; + } + .responsive-at-root { + color: #fff; + } + .variants-at-root { + color: orange; + } + .both-at-root { + color: pink; + } + @media (min-width: 768px) { + .md\:focus\:responsive-in-components:focus { + color: #00f; + } + .md\:focus\:variants-in-components:focus { + color: red; + } + .md\:focus\:both-in-components:focus { + color: green; + } + .md\:focus\:responsive-in-utilities:focus { + color: #00f; + } + .md\:focus\:variants-in-utilities:focus { + color: red; + } + .md\:focus\:both-in-utilities:focus { + color: green; + } + .md\:focus\:responsive-at-root:focus { + color: #fff; + } + .md\:focus\:variants-at-root:focus { + color: orange; + } + .md\:focus\:both-at-root:focus { + color: pink; + } + } + `) }) }) diff --git a/tests/safelist.test.js b/tests/safelist.test.js index cbbd1e245..e2621f846 100644 --- a/tests/safelist.test.js +++ b/tests/safelist.test.js @@ -1,636 +1,491 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('should not safelist anything', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should not safelist anything', () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist strings', () => { - let config = { - content: [{ raw: html`
` }], - safelist: ['mt-[20px]', 'font-bold', 'text-gray-200', 'hover:underline'], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .mt-\[20px\] { - margin-top: 20px; - } - .font-bold { - font-weight: 700; - } - .uppercase { - text-transform: uppercase; - } - .text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); - } - .hover\:underline:hover { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .mt-\[20px\] { - margin-top: 20px; - } - .font-bold { - font-weight: 700; - } - .uppercase { - text-transform: uppercase; - } - .text-gray-200 { - color: #e5e7eb; - } - .hover\:underline:hover { - text-decoration-line: underline; - } - `) - }) - }) - - it('should safelist based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .hover\:bg-red-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - background-color: #fee2e2; - } - .hover\:bg-red-200:hover { - background-color: #fecaca; - } - `) - }) - }) - - it('should not generate duplicates', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - 'uppercase', - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .hover\:bg-red-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - background-color: #fee2e2; - } - .hover\:bg-red-200:hover { - background-color: #fecaca; - } - `) - }) - }) - - it('should safelist when using a custom prefix', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^tw-bg-red-(100|200)$/g, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .tw-bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .tw-bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .tw-uppercase { - text-transform: uppercase; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .tw-bg-red-100 { - background-color: #fee2e2; - } - .tw-bg-red-200 { - background-color: #fecaca; - } - .tw-uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist when an empty list is provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist when an sparse/holey list is provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [, , ,], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist any invalid variants if provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['foo', 'bar'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist negatives based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^-top-1$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .-top-1 { - top: -0.25rem; - } - .uppercase { - text-transform: uppercase; - } - .hover\:-top-1:hover { - top: -0.25rem; - } - `) - }) - }) - - it('should safelist negatives based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-red-(400|500)(\/(40|50))?$/, - variants: ['hover'], - }, - { - pattern: /^(fill|ring|text)-red-200\/50$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .bg-red-400\/40 { - background-color: #f8717166; - } - .bg-red-400\/50 { - background-color: #f8717180; - } - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .bg-red-500\/40 { - background-color: #ef444466; - } - .bg-red-500\/50 { - background-color: #ef444480; - } - .fill-red-200\/50 { - fill: #fecaca80; - } - .uppercase { - text-transform: uppercase; - } - .text-red-200\/50 { - color: #fecaca80; - } - .ring-red-200\/50 { - --tw-ring-color: #fecaca80; - } - .hover\:bg-red-400:hover { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .hover\:bg-red-400\/40:hover { - background-color: #f8717166; - } - .hover\:bg-red-400\/50:hover { - background-color: #f8717180; - } - .hover\:bg-red-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .hover\:bg-red-500\/40:hover { - background-color: #ef444466; - } - .hover\:bg-red-500\/50:hover { - background-color: #ef444480; - } - .hover\:fill-red-200\/50:hover { - fill: #fecaca80; - } - .hover\:text-red-200\/50:hover { - color: #fecaca80; - } - .hover\:ring-red-200\/50:hover { - --tw-ring-color: #fecaca80; - } - `) - }) - }) - - it('should safelist pattern regex with !important selector', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [{ pattern: /^!grid-cols-(4|5|6)$/ }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\!grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)) !important; - } - .\!grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)) !important; - } - .\!grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)) !important; - } - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist pattern regex with custom prefix along with !important selector', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - safelist: [{ pattern: /^!tw-grid-cols-(4|5|6)$/ }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\!tw-grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)) !important; - } - .\!tw-grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)) !important; - } - .\!tw-grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)) !important; - } - .tw-uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist pattern regex having !important selector with variants', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^!bg-gray-(500|600|700|800)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-500 { - --tw-bg-opacity: 1 !important; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-600 { - --tw-bg-opacity: 1 !important; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-700 { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-800 { - --tw-bg-opacity: 1 !important; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; - } - .uppercase { - text-transform: uppercase; - } - .hover\:\!bg-gray-500:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-600:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-700:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-800:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-500 { - background-color: #6b7280 !important; - } - .\!bg-gray-600 { - background-color: #4b5563 !important; - } - .\!bg-gray-700 { - background-color: #374151 !important; - } - .\!bg-gray-800 { - background-color: #1f2937 !important; - } - .uppercase { - text-transform: uppercase; - } - .hover\:\!bg-gray-500:hover { - background-color: #6b7280 !important; - } - .hover\:\!bg-gray-600:hover { - background-color: #4b5563 !important; - } - .hover\:\!bg-gray-700:hover { - background-color: #374151 !important; - } - .hover\:\!bg-gray-800:hover { - background-color: #1f2937 !important; - } - `) - }) - }) - - it('should safelist multiple patterns with !important selector', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^!text-gray-(700|800|900)$/, - variants: ['hover'], - }, - { - pattern: /^!bg-gray-(200|300|400)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-200 { - --tw-bg-opacity: 1 !important; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-300 { - --tw-bg-opacity: 1 !important; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-400 { - --tw-bg-opacity: 1 !important; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; - } - .uppercase { - text-transform: uppercase; - } - .\!text-gray-700 { - --tw-text-opacity: 1 !important; - color: rgb(55 65 81 / var(--tw-text-opacity)) !important; - } - .\!text-gray-800 { - --tw-text-opacity: 1 !important; - color: rgb(31 41 55 / var(--tw-text-opacity)) !important; - } - .\!text-gray-900 { - --tw-text-opacity: 1 !important; - color: rgb(17 24 39 / var(--tw-text-opacity)) !important; - } - .hover\:\!bg-gray-200:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-300:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-400:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; - } - .hover\:\!text-gray-700:hover { - --tw-text-opacity: 1 !important; - color: rgb(55 65 81 / var(--tw-text-opacity)) !important; - } - .hover\:\!text-gray-800:hover { - --tw-text-opacity: 1 !important; - color: rgb(31 41 55 / var(--tw-text-opacity)) !important; - } - .hover\:\!text-gray-900:hover { - --tw-text-opacity: 1 !important; - color: rgb(17 24 39 / var(--tw-text-opacity)) !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-200 { - background-color: #e5e7eb !important; - } - .\!bg-gray-300 { - background-color: #d1d5db !important; - } - .\!bg-gray-400 { - background-color: #9ca3af !important; - } - .uppercase { - text-transform: uppercase; - } - .\!text-gray-700 { - color: #374151 !important; - } - .\!text-gray-800 { - color: #1f2937 !important; - } - .\!text-gray-900 { - color: #111827 !important; - } - .hover\:\!bg-gray-200:hover { - background-color: #e5e7eb !important; - } - .hover\:\!bg-gray-300:hover { - background-color: #d1d5db !important; - } - .hover\:\!bg-gray-400:hover { - background-color: #9ca3af !important; - } - .hover\:\!text-gray-700:hover { - color: #374151 !important; - } - .hover\:\!text-gray-800:hover { - color: #1f2937 !important; - } - .hover\:\!text-gray-900:hover { - color: #111827 !important; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist strings', () => { + let config = { + content: [{ raw: html`
` }], + safelist: ['mt-[20px]', 'font-bold', 'text-gray-200', 'hover:underline'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .mt-\[20px\] { + margin-top: 20px; + } + .font-bold { + font-weight: 700; + } + .uppercase { + text-transform: uppercase; + } + .text-gray-200 { + --tw-text-opacity: 1; + color: rgb(229 231 235 / var(--tw-text-opacity)); + } + .hover\:underline:hover { + text-decoration-line: underline; + } + `) + }) +}) + +it('should safelist based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + .hover\:bg-red-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .hover\:bg-red-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should not generate duplicates', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + 'uppercase', + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + .hover\:bg-red-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .hover\:bg-red-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should safelist when using a custom prefix', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^tw-bg-red-(100|200)$/g, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .tw-bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .tw-uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist when an empty list is provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist when an sparse/holey list is provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [, , ,], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist any invalid variants if provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['foo', 'bar'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist negatives based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^-top-1$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-top-1 { + top: -0.25rem; + } + .uppercase { + text-transform: uppercase; + } + .hover\:-top-1:hover { + top: -0.25rem; + } + `) + }) +}) + +it('should safelist negatives based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-red-(400|500)(\/(40|50))?$/, + variants: ['hover'], + }, + { + pattern: /^(fill|ring|text)-red-200\/50$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-400 { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .bg-red-400\/40 { + background-color: #f8717166; + } + .bg-red-400\/50 { + background-color: #f8717180; + } + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .bg-red-500\/40 { + background-color: #ef444466; + } + .bg-red-500\/50 { + background-color: #ef444480; + } + .fill-red-200\/50 { + fill: #fecaca80; + } + .uppercase { + text-transform: uppercase; + } + .text-red-200\/50 { + color: #fecaca80; + } + .ring-red-200\/50 { + --tw-ring-color: #fecaca80; + } + .hover\:bg-red-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .hover\:bg-red-400\/40:hover { + background-color: #f8717166; + } + .hover\:bg-red-400\/50:hover { + background-color: #f8717180; + } + .hover\:bg-red-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .hover\:bg-red-500\/40:hover { + background-color: #ef444466; + } + .hover\:bg-red-500\/50:hover { + background-color: #ef444480; + } + .hover\:fill-red-200\/50:hover { + fill: #fecaca80; + } + .hover\:text-red-200\/50:hover { + color: #fecaca80; + } + .hover\:ring-red-200\/50:hover { + --tw-ring-color: #fecaca80; + } + `) + }) +}) + +it('should safelist pattern regex with !important selector', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [{ pattern: /^!grid-cols-(4|5|6)$/ }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\!grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } + .\!grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)) !important; + } + .\!grid-cols-6 { + grid-template-columns: repeat(6, minmax(0, 1fr)) !important; + } + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist pattern regex with custom prefix along with !important selector', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + safelist: [{ pattern: /^!tw-grid-cols-(4|5|6)$/ }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\!tw-grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } + .\!tw-grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)) !important; + } + .\!tw-grid-cols-6 { + grid-template-columns: repeat(6, minmax(0, 1fr)) !important; + } + .tw-uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist pattern regex having !important selector with variants', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^!bg-gray-(500|600|700|800)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!bg-gray-500 { + --tw-bg-opacity: 1 !important; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-600 { + --tw-bg-opacity: 1 !important; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-700 { + --tw-bg-opacity: 1 !important; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-800 { + --tw-bg-opacity: 1 !important; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; + } + .uppercase { + text-transform: uppercase; + } + .hover\:\!bg-gray-500:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-600:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-700:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-800:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; + } + `) + }) +}) + +it('should safelist multiple patterns with !important selector', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^!text-gray-(700|800|900)$/, + variants: ['hover'], + }, + { + pattern: /^!bg-gray-(200|300|400)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!bg-gray-200 { + --tw-bg-opacity: 1 !important; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-300 { + --tw-bg-opacity: 1 !important; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-400 { + --tw-bg-opacity: 1 !important; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; + } + .uppercase { + text-transform: uppercase; + } + .\!text-gray-700 { + --tw-text-opacity: 1 !important; + color: rgb(55 65 81 / var(--tw-text-opacity)) !important; + } + .\!text-gray-800 { + --tw-text-opacity: 1 !important; + color: rgb(31 41 55 / var(--tw-text-opacity)) !important; + } + .\!text-gray-900 { + --tw-text-opacity: 1 !important; + color: rgb(17 24 39 / var(--tw-text-opacity)) !important; + } + .hover\:\!bg-gray-200:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-300:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-400:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; + } + .hover\:\!text-gray-700:hover { + --tw-text-opacity: 1 !important; + color: rgb(55 65 81 / var(--tw-text-opacity)) !important; + } + .hover\:\!text-gray-800:hover { + --tw-text-opacity: 1 !important; + color: rgb(31 41 55 / var(--tw-text-opacity)) !important; + } + .hover\:\!text-gray-900:hover { + --tw-text-opacity: 1 !important; + color: rgb(17 24 39 / var(--tw-text-opacity)) !important; + } + `) }) }) diff --git a/tests/screenAtRule.test.js b/tests/screenAtRule.test.js index 6352fcde0..af13b5ddf 100644 --- a/tests/screenAtRule.test.js +++ b/tests/screenAtRule.test.js @@ -1,60 +1,58 @@ import postcss from 'postcss' import plugin from '../src/lib/substituteScreenAtRules' import config from '../stubs/config.full.js' -import { crosscheck, css } from './util/run' +import { css } from './util/run' function run(input, opts = config) { return postcss([plugin({ tailwindConfig: opts })]).process(input, { from: undefined }) } -crosscheck(() => { - test('it can generate media queries from configured screen sizes', () => { - let input = css` - @screen sm { +test('it can generate media queries from configured screen sizes', () => { + let input = css` + @screen sm { + .banana { + color: yellow; + } + } + @screen md { + .banana { + color: red; + } + } + @screen lg { + .banana { + color: green; + } + } + ` + + return run(input, { + theme: { + screens: { + sm: '500px', + md: '750px', + lg: '1000px', + }, + }, + separator: ':', + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { .banana { color: yellow; } } - @screen md { + @media (min-width: 750px) { .banana { color: red; } } - @screen lg { + @media (min-width: 1000px) { .banana { color: green; } } - ` - - return run(input, { - theme: { - screens: { - sm: '500px', - md: '750px', - lg: '1000px', - }, - }, - separator: ':', - }).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .banana { - color: #ff0; - } - } - @media (min-width: 750px) { - .banana { - color: red; - } - } - @media (min-width: 1000px) { - .banana { - color: green; - } - } - `) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) }) diff --git a/tests/shared-state.test.js b/tests/shared-state.test.js index 4791d07dc..a3a9f2870 100644 --- a/tests/shared-state.test.js +++ b/tests/shared-state.test.js @@ -1,23 +1,20 @@ import { resolveDebug } from '../src/lib/sharedState' -import { crosscheck } from './util/run' -crosscheck(() => { - it.each` - value | expected - ${'true'} | ${true} - ${'1'} | ${true} - ${'false'} | ${false} - ${'0'} | ${false} - ${'*'} | ${true} - ${'tailwindcss'} | ${true} - ${'tailwindcss:*'} | ${true} - ${'other,tailwindcss'} | ${true} - ${'other,tailwindcss:*'} | ${true} - ${'other,-tailwindcss'} | ${false} - ${'other,-tailwindcss:*'} | ${false} - ${'-tailwindcss'} | ${false} - ${'-tailwindcss:*'} | ${false} - `('should resolve the debug ($value) flag correctly ($expected)', ({ value, expected }) => { - expect(resolveDebug(value)).toBe(expected) - }) +it.each` + value | expected + ${'true'} | ${true} + ${'1'} | ${true} + ${'false'} | ${false} + ${'0'} | ${false} + ${'*'} | ${true} + ${'tailwindcss'} | ${true} + ${'tailwindcss:*'} | ${true} + ${'other,tailwindcss'} | ${true} + ${'other,tailwindcss:*'} | ${true} + ${'other,-tailwindcss'} | ${false} + ${'other,-tailwindcss:*'} | ${false} + ${'-tailwindcss'} | ${false} + ${'-tailwindcss:*'} | ${false} +`('should resolve the debug ($value) flag correctly ($expected)', ({ value, expected }) => { + expect(resolveDebug(value)).toBe(expected) }) diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index dc0092dbc..4cfcd62d8 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -1,532 +1,585 @@ import postcss from 'postcss' import { parseSourceMaps } from './util/source-maps' -import { crosscheck, runWithSourceMaps as run, html, css, map } from './util/run' +import { runWithSourceMaps as run, html, css, map } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('apply generates source maps') - stable.test('apply generates source maps', async () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - .with-declaration { - background-color: red; - @apply h-4 w-4 bg-green-500; - } - - .with-comment { - /* sourcemap will work here too */ - @apply h-4 w-4 bg-red-500; - } - - .just-apply { - @apply h-4 w-4 bg-black; - } - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 2:6', - '3:8-29 -> 3:8-29', - '4:8-35 -> 4:8-20', - '4:8-35 -> 5:8-19', - '4:8-35 -> 6:8-26', - '4:8-35 -> 7:8-63', - '5:6 -> 8:6', - '7:6 -> 10:6', - '8:8-41 -> 11:8-41', - '9:8-33 -> 12:8-20', - '9:8-33 -> 13:8-19', - '9:8-33 -> 14:8-26', - '9:8-33 -> 15:8-63', - '10:6 -> 16:6', - '13:8 -> 18:6', - '13:8-31 -> 19:8-20', - '13:8-31 -> 20:8-19', - '13:8-31 -> 21:8-26', - '13:8 -> 22:8', - '13:31 -> 23:0', - ]) - }) - - oxide.test.todo('preflight + base have source maps') - stable.test('preflight + base have source maps', async () => { - let config = { - content: [], - } - - let input = css` - @tailwind base; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:20-6 -> 3:1-2', - '2:20 -> 6:1', - '2:6 -> 8:0', - '2:6-20 -> 11:2-32', - '2:6-20 -> 12:2-25', - '2:6-20 -> 13:2-29', - '2:6-20 -> 14:2-31', - '2:20 -> 15:0', - '2:6 -> 17:0', - '2:6-20 -> 19:2-18', - '2:20 -> 20:0', - '2:6 -> 22:0', - '2:20 -> 29:1', - '2:6 -> 31:0', - '2:6-20 -> 32:2-26', - '2:6-20 -> 33:2-40', - '2:6-20 -> 34:2-26', - '2:6-20 -> 35:2-21', - '2:6-20 -> 36:2-230', - '2:6-20 -> 37:2-39', - '2:6-20 -> 38:2-41', - '2:20 -> 39:0', - '2:6 -> 41:0', - '2:20 -> 44:1', - '2:6 -> 46:0', - '2:6-20 -> 47:2-19', - '2:6-20 -> 48:2-30', - '2:20 -> 49:0', - '2:6 -> 51:0', - '2:20 -> 55:1', - '2:6 -> 57:0', - '2:6-20 -> 58:2-19', - '2:6-20 -> 59:2-24', - '2:6-20 -> 60:2-31', - '2:20 -> 61:0', - '2:6 -> 63:0', - '2:20 -> 65:1', - '2:6 -> 67:0', - '2:6-20 -> 68:2-35', - '2:20 -> 69:0', - '2:6 -> 71:0', - '2:20 -> 73:1', - '2:6 -> 75:0', - '2:6-20 -> 81:2-20', - '2:6-20 -> 82:2-22', - '2:20 -> 83:0', - '2:6 -> 85:0', - '2:20 -> 87:1', - '2:6 -> 89:0', - '2:6-20 -> 90:2-16', - '2:6-20 -> 91:2-26', - '2:20 -> 92:0', - '2:6 -> 94:0', - '2:20 -> 96:1', - '2:6 -> 98:0', - '2:6-20 -> 100:2-21', - '2:20 -> 101:0', - '2:6 -> 103:0', - '2:20 -> 106:1', - '2:6 -> 108:0', - '2:6-20 -> 112:2-121', - '2:6-20 -> 113:2-24', - '2:20 -> 114:0', - '2:6 -> 116:0', - '2:20 -> 118:1', - '2:6 -> 120:0', - '2:6-20 -> 121:2-16', - '2:20 -> 122:0', - '2:6 -> 124:0', - '2:20 -> 126:1', - '2:6 -> 128:0', - '2:6-20 -> 130:2-16', - '2:6-20 -> 131:2-16', - '2:6-20 -> 132:2-20', - '2:6-20 -> 133:2-26', - '2:20 -> 134:0', - '2:6 -> 136:0', - '2:6-20 -> 137:2-17', - '2:20 -> 138:0', - '2:6 -> 140:0', - '2:6-20 -> 141:2-13', - '2:20 -> 142:0', - '2:6 -> 144:0', - '2:20 -> 148:1', - '2:6 -> 150:0', - '2:6-20 -> 151:2-24', - '2:6-20 -> 152:2-31', - '2:6-20 -> 153:2-35', - '2:20 -> 154:0', - '2:6 -> 156:0', - '2:20 -> 160:1', - '2:6 -> 162:0', - '2:6-20 -> 167:2-30', - '2:6-20 -> 168:2-25', - '2:6-20 -> 169:2-30', - '2:6-20 -> 170:2-30', - '2:6-20 -> 171:2-24', - '2:6-20 -> 172:2-19', - '2:6-20 -> 173:2-20', - '2:20 -> 174:0', - '2:6 -> 176:0', - '2:20 -> 178:1', - '2:6 -> 180:0', - '2:6-20 -> 182:2-22', - '2:20 -> 183:0', - '2:6 -> 185:0', - '2:20 -> 188:1', - '2:6 -> 190:0', - '2:6-20 -> 194:2-36', - '2:6-20 -> 195:2-39', - '2:6-20 -> 196:2-32', - '2:20 -> 197:0', - '2:6 -> 199:0', - '2:20 -> 201:1', - '2:6 -> 203:0', - '2:6-20 -> 204:2-15', - '2:20 -> 205:0', - '2:6 -> 207:0', - '2:20 -> 209:1', - '2:6 -> 211:0', - '2:6-20 -> 212:2-18', - '2:20 -> 213:0', - '2:6 -> 215:0', - '2:20 -> 217:1', - '2:6 -> 219:0', - '2:6-20 -> 220:2-26', - '2:20 -> 221:0', - '2:6 -> 223:0', - '2:20 -> 225:1', - '2:6 -> 227:0', - '2:6-20 -> 229:2-14', - '2:20 -> 230:0', - '2:6 -> 232:0', - '2:20 -> 235:1', - '2:6 -> 237:0', - '2:6-20 -> 238:2-39', - '2:6-20 -> 239:2-30', - '2:20 -> 240:0', - '2:6 -> 242:0', - '2:20 -> 244:1', - '2:6 -> 246:0', - '2:6-20 -> 247:2-26', - '2:20 -> 248:0', - '2:6 -> 250:0', - '2:20 -> 253:1', - '2:6 -> 255:0', - '2:6-20 -> 256:2-36', - '2:6-20 -> 257:2-23', - '2:20 -> 258:0', - '2:6 -> 260:0', - '2:20 -> 262:1', - '2:6 -> 264:0', - '2:6-20 -> 265:2-20', - '2:20 -> 266:0', - '2:6 -> 268:0', - '2:20 -> 270:1', - '2:6 -> 272:0', - '2:6-20 -> 285:2-11', - '2:20 -> 286:0', - '2:6 -> 288:0', - '2:6-20 -> 289:2-11', - '2:6-20 -> 290:2-12', - '2:20 -> 291:0', - '2:6 -> 293:0', - '2:6-20 -> 294:2-12', - '2:20 -> 295:0', - '2:6 -> 297:0', - '2:6-20 -> 300:2-18', - '2:6-20 -> 301:2-11', - '2:6-20 -> 302:2-12', - '2:20 -> 303:0', - '2:6 -> 305:0', - '2:20 -> 307:1', - '2:6 -> 309:0', - '2:6-20 -> 310:2-18', - '2:20 -> 311:0', - '2:6 -> 313:0', - '2:20 -> 316:1', - '2:6 -> 318:0', - '2:6-20 -> 320:2-20', - '2:6-20 -> 321:2-24', - '2:20 -> 322:0', - '2:6 -> 324:0', - '2:20 -> 326:1', - '2:6 -> 328:0', - '2:6-20 -> 330:2-17', - '2:20 -> 331:0', - '2:6 -> 333:0', - '2:20 -> 335:1', - '2:6 -> 336:0', - '2:6-20 -> 337:2-17', - '2:20 -> 338:0', - '2:6 -> 340:0', - '2:20 -> 344:1', - '2:6 -> 346:0', - '2:6-20 -> 354:2-24', - '2:6-20 -> 355:2-32', - '2:20 -> 356:0', - '2:6 -> 358:0', - '2:20 -> 360:1', - '2:6 -> 362:0', - '2:6-20 -> 364:2-17', - '2:6-20 -> 365:2-14', - '2:20 -> 366:0', - '2:6-20 -> 368:0-72', - '2:6 -> 369:0', - '2:6-20 -> 370:2-15', - '2:20 -> 371:0', - '2:6 -> 373:0', - '2:6-20 -> 374:2-26', - '2:6-20 -> 375:2-26', - '2:6-20 -> 376:2-21', - '2:6-20 -> 377:2-21', - '2:6-20 -> 378:2-16', - '2:6-20 -> 379:2-16', - '2:6-20 -> 380:2-16', - '2:6-20 -> 381:2-17', - '2:6-20 -> 382:2-17', - '2:6-20 -> 383:2-15', - '2:6-20 -> 384:2-15', - '2:6-20 -> 385:2-20', - '2:6-20 -> 386:2-40', - '2:6-20 -> 387:2-32', - '2:6-20 -> 388:2-31', - '2:6-20 -> 389:2-30', - '2:6-20 -> 390:2-17', - '2:6-20 -> 391:2-22', - '2:6-20 -> 392:2-24', - '2:6-20 -> 393:2-25', - '2:6-20 -> 394:2-26', - '2:6-20 -> 395:2-20', - '2:6-20 -> 396:2-29', - '2:6-20 -> 397:2-30', - '2:6-20 -> 398:2-40', - '2:6-20 -> 399:2-36', - '2:6-20 -> 400:2-29', - '2:6-20 -> 401:2-24', - '2:6-20 -> 402:2-32', - '2:6-20 -> 403:2-14', - '2:6-20 -> 404:2-20', - '2:6-20 -> 405:2-18', - '2:6-20 -> 406:2-19', - '2:6-20 -> 407:2-20', - '2:6-20 -> 408:2-16', - '2:6-20 -> 409:2-18', - '2:6-20 -> 410:2-15', - '2:6-20 -> 411:2-21', - '2:6-20 -> 412:2-23', - '2:6-20 -> 413:2-29', - '2:6-20 -> 414:2-27', - '2:6-20 -> 415:2-28', - '2:6-20 -> 416:2-29', - '2:6-20 -> 417:2-25', - '2:6-20 -> 418:2-26', - '2:6-20 -> 419:2-27', - '2:6 -> 420:2', - '2:20 -> 421:0', - '2:6 -> 423:0', - '2:6-20 -> 424:2-26', - '2:6-20 -> 425:2-26', - '2:6-20 -> 426:2-21', - '2:6-20 -> 427:2-21', - '2:6-20 -> 428:2-16', - '2:6-20 -> 429:2-16', - '2:6-20 -> 430:2-16', - '2:6-20 -> 431:2-17', - '2:6-20 -> 432:2-17', - '2:6-20 -> 433:2-15', - '2:6-20 -> 434:2-15', - '2:6-20 -> 435:2-20', - '2:6-20 -> 436:2-40', - '2:6-20 -> 437:2-32', - '2:6-20 -> 438:2-31', - '2:6-20 -> 439:2-30', - '2:6-20 -> 440:2-17', - '2:6-20 -> 441:2-22', - '2:6-20 -> 442:2-24', - '2:6-20 -> 443:2-25', - '2:6-20 -> 444:2-26', - '2:6-20 -> 445:2-20', - '2:6-20 -> 446:2-29', - '2:6-20 -> 447:2-30', - '2:6-20 -> 448:2-40', - '2:6-20 -> 449:2-36', - '2:6-20 -> 450:2-29', - '2:6-20 -> 451:2-24', - '2:6-20 -> 452:2-32', - '2:6-20 -> 453:2-14', - '2:6-20 -> 454:2-20', - '2:6-20 -> 455:2-18', - '2:6-20 -> 456:2-19', - '2:6-20 -> 457:2-20', - '2:6-20 -> 458:2-16', - '2:6-20 -> 459:2-18', - '2:6-20 -> 460:2-15', - '2:6-20 -> 461:2-21', - '2:6-20 -> 462:2-23', - '2:6-20 -> 463:2-29', - '2:6-20 -> 464:2-27', - '2:6-20 -> 465:2-28', - '2:6-20 -> 466:2-29', - '2:6-20 -> 467:2-25', - '2:6-20 -> 468:2-26', - '2:6-20 -> 469:2-27', - '2:6 -> 470:2', - '2:20 -> 471:0', - ]) - }) - - oxide.test.todo('utilities have source maps') - stable.test('utilities have source maps', async () => { - let config = { - content: [{ raw: `text-red-500` }], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toStrictEqual([ - '2:6 -> 1:0', - '2:6-25 -> 2:4-24', - '2:6 -> 3:4', - '2:25 -> 4:0', - ]) - }) - - oxide.test.todo('components have source maps') - stable.test('components have source maps', async () => { - let config = { - content: [{ raw: `container` }], - } - - let input = css` - @tailwind components; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:6 -> 2:4', - '2:26 -> 3:0', - '2:6 -> 4:0', - '2:6 -> 5:4', - '2:6 -> 6:8', - '2:26 -> 7:4', - '2:26 -> 8:0', - '2:6 -> 9:0', - '2:6 -> 10:4', - '2:6 -> 11:8', - '2:26 -> 12:4', - '2:26 -> 13:0', - '2:6 -> 14:0', - '2:6 -> 15:4', - '2:6 -> 16:8', - '2:26 -> 17:4', - '2:26 -> 18:0', - '2:6 -> 19:0', - '2:6 -> 20:4', - '2:6 -> 21:8', - '2:26 -> 22:4', - '2:26 -> 23:0', - '2:6 -> 24:0', - '2:6 -> 25:4', - '2:6 -> 26:8', - '2:26 -> 27:4', - '2:26 -> 28:0', - ]) - }) - - oxide.test.todo('source maps for layer rules are not rewritten to point to @tailwind directives') - stable.test( - 'source maps for layer rules are not rewritten to point to @tailwind directives', - async () => { - let config = { - content: [{ raw: `font-normal foo hover:foo` }], - } - - let utilitiesFile = postcss.parse( - css` - @tailwind utilities; +test('apply generates source maps', async () => { + let config = { + content: [ + { + raw: html` +
+
+
`, - { from: 'components.css', map: { prev: map } } - ) + }, + ], + corePlugins: { preflight: false }, + } - let mainCssFile = postcss.parse( - css` - @layer utilities { - .foo { - background-color: red; - } - } - `, - { from: 'input.css', map: { prev: map } } - ) - - // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` - let input = postcss.root({ - nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], - source: mainCssFile.source, - }) - - let result = await run(input, config) - - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - - // And we should see that the source map for the layer rule is not rewritten - // to point to the @tailwind directive but instead points to the original - expect(sources.length).toBe(2) - expect(sources).toEqual(['components.css', 'input.css']) - - expect(annotations).toEqual([ - '2:10 -> 1:0', - '2:10 -> 2:14', - '2:29 -> 3:0', - '3:12 -> 4:12', - '4:14-35 -> 5:14-35', - '5:12 -> 6:12', - '3:12 -> 7:12', - '4:14-35 -> 8:14-35', - '5:12 -> 9:12', - ]) + let input = css` + .with-declaration { + background-color: red; + @apply h-4 w-4 bg-green-500; } - ) + + .with-comment { + /* sourcemap will work here too */ + @apply h-4 w-4 bg-red-500; + } + + .just-apply { + @apply h-4 w-4 bg-black; + } + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-20 -> 2:2-20", + "3:2-23 -> 3:2-23", + "4:2-57 -> 4:2-57", + "5:2-13 -> 5:2-13", + "6:2-14 -> 6:2-14", + "7:0 -> 7:0", + "7:4 -> 9:0", + "10:2-20 -> 10:2-20", + "11:2-57 -> 11:2-57", + "12:2-13 -> 12:2-13", + "13:2-14 -> 13:2-14", + "14:0 -> 14:0", + "13:6 -> 16:0", + "17:2-20 -> 17:2-20", + "18:2-53 -> 18:2-53", + "19:2-13 -> 19:2-13", + "20:2-14 -> 20:2-14", + "21:0 -> 21:0", + ] + `) +}) + +test('preflight + base have source maps', async () => { + let config = { + content: [], + } + + let input = css` + @tailwind base; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-24 -> 2:2-24", + "3:2-25 -> 3:2-25", + "4:0 -> 4:0", + "2:4 -> 6:0", + "7:2-18 -> 7:2-18", + "8:0 -> 8:0", + "2:4 -> 10:0", + "11:2-32 -> 11:2-32", + "12:2-13 -> 12:2-13", + "13:2-31 -> 13:2-31", + "14:2-33 -> 14:2-33", + "15:2-208 -> 15:2-208", + "16:2-18 -> 16:2-18", + "17:0 -> 17:0", + "2:4 -> 19:0", + "20:2-22 -> 20:2-22", + "21:2-11 -> 21:2-11", + "22:0 -> 22:0", + "2:4 -> 24:0", + "25:2-16 -> 25:2-16", + "26:2-23 -> 26:2-23", + "27:2-11 -> 27:2-11", + "28:0 -> 28:0", + "2:4 -> 30:0", + "31:2-43 -> 31:2-43", + "32:2-35 -> 32:2-35", + "33:0 -> 33:0", + "2:4 -> 35:0", + "36:2-20 -> 36:2-20", + "37:2-22 -> 37:2-22", + "38:0 -> 38:0", + "2:4 -> 40:0", + "41:2-16 -> 41:2-16", + "42:2-34 -> 42:2-34", + "43:2-26 -> 43:2-26", + "44:0 -> 44:0", + "2:4 -> 46:0", + "47:2-21 -> 47:2-21", + "48:0 -> 48:0", + "2:4 -> 50:0", + "51:2-109 -> 51:2-109", + "52:2-16 -> 52:2-16", + "53:0 -> 53:0", + "2:4 -> 55:0", + "56:2-16 -> 56:2-16", + "57:0 -> 57:0", + "2:4 -> 59:0", + "60:2-26 -> 60:2-26", + "61:2-16 -> 61:2-16", + "62:2-16 -> 62:2-16", + "63:2-20 -> 63:2-20", + "64:0 -> 64:0", + "2:4 -> 66:0", + "67:2-16 -> 67:2-16", + "68:0 -> 68:0", + "2:4 -> 70:0", + "71:2-12 -> 71:2-12", + "72:0 -> 72:0", + "2:4 -> 74:0", + "75:2-16 -> 75:2-16", + "76:2-23 -> 76:2-23", + "77:2-27 -> 77:2-27", + "78:0 -> 78:0", + "2:4 -> 80:0", + "81:2-32 -> 81:2-32", + "82:2-34 -> 82:2-34", + "83:2-22 -> 83:2-22", + "84:2-17 -> 84:2-17", + "85:2-22 -> 85:2-22", + "86:2-22 -> 86:2-22", + "87:2-16 -> 87:2-16", + "88:2-11 -> 88:2-11", + "89:2-12 -> 89:2-12", + "90:0 -> 90:0", + "2:4 -> 92:0", + "93:2-22 -> 93:2-22", + "94:0 -> 94:0", + "2:4 -> 96:0", + "97:2-28 -> 97:2-28", + "98:2-25 -> 98:2-25", + "99:2-24 -> 99:2-24", + "100:0 -> 100:0", + "2:4 -> 102:0", + "103:2-15 -> 103:2-15", + "104:0 -> 104:0", + "2:4 -> 106:0", + "107:2-18 -> 107:2-18", + "108:0 -> 108:0", + "2:4 -> 110:0", + "111:2-26 -> 111:2-26", + "112:0 -> 112:0", + "2:4 -> 114:0", + "115:2-14 -> 115:2-14", + "116:0 -> 116:0", + "2:4 -> 118:0", + "119:2-31 -> 119:2-31", + "120:2-22 -> 120:2-22", + "121:0 -> 121:0", + "2:4 -> 123:0", + "124:2-26 -> 124:2-26", + "125:0 -> 125:0", + "2:4 -> 127:0", + "128:2-28 -> 128:2-28", + "129:2-15 -> 129:2-15", + "130:0 -> 130:0", + "2:4 -> 132:0", + "133:2-20 -> 133:2-20", + "134:0 -> 134:0", + "2:4 -> 136:0", + "137:2-11 -> 137:2-11", + "138:0 -> 138:0", + "2:4 -> 140:0", + "141:2-11 -> 141:2-11", + "142:2-12 -> 142:2-12", + "143:0 -> 143:0", + "2:4 -> 145:0", + "146:2-12 -> 146:2-12", + "147:0 -> 147:0", + "2:4 -> 149:0", + "150:2-11 -> 150:2-11", + "151:2-12 -> 151:2-12", + "152:2-18 -> 152:2-18", + "153:0 -> 153:0", + "2:4 -> 155:0", + "156:2-12 -> 156:2-12", + "157:0 -> 157:0", + "2:4 -> 159:0", + "160:2-18 -> 160:2-18", + "161:0 -> 161:0", + "2:4 -> 163:0", + "164:2-12 -> 164:2-12", + "165:2-16 -> 165:2-16", + "166:0 -> 166:0", + "2:4 -> 168:0", + "169:2-17 -> 169:2-17", + "170:0 -> 170:0", + "2:4 -> 172:0", + "173:2-17 -> 173:2-17", + "174:0 -> 174:0", + "2:4 -> 176:0", + "177:2-24 -> 177:2-24", + "178:2-16 -> 178:2-16", + "179:0 -> 179:0", + "2:4 -> 181:0", + "182:2-17 -> 182:2-17", + "183:2-14 -> 183:2-14", + "184:0 -> 184:0", + "2:4 -> 186:0", + "187:2-15 -> 187:2-15", + "188:0 -> 188:0", + "2:4 -> 190:0", + "191:2-26 -> 191:2-26", + "192:2-26 -> 192:2-26", + "193:2-21 -> 193:2-21", + "194:2-21 -> 194:2-21", + "195:2-16 -> 195:2-16", + "196:2-16 -> 196:2-16", + "197:2-16 -> 197:2-16", + "198:2-17 -> 198:2-17", + "199:2-17 -> 199:2-17", + "200:2-14 -> 200:2-14", + "201:2-14 -> 201:2-14", + "202:2-19 -> 202:2-19", + "203:2-40 -> 203:2-40", + "204:2-31 -> 204:2-31", + "205:2-30 -> 205:2-30", + "206:2-29 -> 206:2-29", + "207:2-16 -> 207:2-16", + "208:2-21 -> 208:2-21", + "209:2-23 -> 209:2-23", + "210:2-24 -> 210:2-24", + "211:2-25 -> 211:2-25", + "212:2-19 -> 212:2-19", + "213:2-29 -> 213:2-29", + "214:2-30 -> 214:2-30", + "215:2-28 -> 215:2-28", + "216:2-36 -> 216:2-36", + "217:2-29 -> 217:2-29", + "218:2-24 -> 218:2-24", + "219:2-32 -> 219:2-32", + "220:2-13 -> 220:2-13", + "221:2-19 -> 221:2-19", + "222:2-17 -> 222:2-17", + "223:2-18 -> 223:2-18", + "224:2-19 -> 224:2-19", + "225:2-15 -> 225:2-15", + "226:2-17 -> 226:2-17", + "227:2-14 -> 227:2-14", + "228:2-20 -> 228:2-20", + "229:2-22 -> 229:2-22", + "230:2-28 -> 230:2-28", + "231:2-26 -> 231:2-26", + "232:2-27 -> 232:2-27", + "233:2-28 -> 233:2-28", + "234:2-24 -> 234:2-24", + "235:2-25 -> 235:2-25", + "236:2-26 -> 236:2-26", + "237:2-23 -> 237:2-23", + "238:0 -> 238:0", + "2:4 -> 240:0", + "241:2-26 -> 241:2-26", + "242:2-26 -> 242:2-26", + "243:2-21 -> 243:2-21", + "244:2-21 -> 244:2-21", + "245:2-16 -> 245:2-16", + "246:2-16 -> 246:2-16", + "247:2-16 -> 247:2-16", + "248:2-17 -> 248:2-17", + "249:2-17 -> 249:2-17", + "250:2-14 -> 250:2-14", + "251:2-14 -> 251:2-14", + "252:2-19 -> 252:2-19", + "253:2-40 -> 253:2-40", + "254:2-31 -> 254:2-31", + "255:2-30 -> 255:2-30", + "256:2-29 -> 256:2-29", + "257:2-16 -> 257:2-16", + "258:2-21 -> 258:2-21", + "259:2-23 -> 259:2-23", + "260:2-24 -> 260:2-24", + "261:2-25 -> 261:2-25", + "262:2-19 -> 262:2-19", + "263:2-29 -> 263:2-29", + "264:2-30 -> 264:2-30", + "265:2-28 -> 265:2-28", + "266:2-36 -> 266:2-36", + "267:2-29 -> 267:2-29", + "268:2-24 -> 268:2-24", + "269:2-32 -> 269:2-32", + "270:2-13 -> 270:2-13", + "271:2-19 -> 271:2-19", + "272:2-17 -> 272:2-17", + "273:2-18 -> 273:2-18", + "274:2-19 -> 274:2-19", + "275:2-15 -> 275:2-15", + "276:2-17 -> 276:2-17", + "277:2-14 -> 277:2-14", + "278:2-20 -> 278:2-20", + "279:2-22 -> 279:2-22", + "280:2-28 -> 280:2-28", + "281:2-26 -> 281:2-26", + "282:2-27 -> 282:2-27", + "283:2-28 -> 283:2-28", + "284:2-24 -> 284:2-24", + "285:2-25 -> 285:2-25", + "286:2-26 -> 286:2-26", + "287:2-23 -> 287:2-23", + "288:0 -> 288:0", + "2:4 -> 290:0", + "291:2-26 -> 291:2-26", + "292:2-26 -> 292:2-26", + "293:2-21 -> 293:2-21", + "294:2-21 -> 294:2-21", + "295:2-16 -> 295:2-16", + "296:2-16 -> 296:2-16", + "297:2-16 -> 297:2-16", + "298:2-17 -> 298:2-17", + "299:2-17 -> 299:2-17", + "300:2-14 -> 300:2-14", + "301:2-14 -> 301:2-14", + "302:2-19 -> 302:2-19", + "303:2-40 -> 303:2-40", + "304:2-31 -> 304:2-31", + "305:2-30 -> 305:2-30", + "306:2-29 -> 306:2-29", + "307:2-16 -> 307:2-16", + "308:2-21 -> 308:2-21", + "309:2-23 -> 309:2-23", + "310:2-24 -> 310:2-24", + "311:2-25 -> 311:2-25", + "312:2-19 -> 312:2-19", + "313:2-29 -> 313:2-29", + "314:2-30 -> 314:2-30", + "315:2-28 -> 315:2-28", + "316:2-36 -> 316:2-36", + "317:2-29 -> 317:2-29", + "318:2-24 -> 318:2-24", + "319:2-32 -> 319:2-32", + "320:2-13 -> 320:2-13", + "321:2-19 -> 321:2-19", + "322:2-17 -> 322:2-17", + "323:2-18 -> 323:2-18", + "324:2-19 -> 324:2-19", + "325:2-15 -> 325:2-15", + "326:2-17 -> 326:2-17", + "327:2-14 -> 327:2-14", + "328:2-20 -> 328:2-20", + "329:2-22 -> 329:2-22", + "330:2-28 -> 330:2-28", + "331:2-26 -> 331:2-26", + "332:2-27 -> 332:2-27", + "333:2-28 -> 333:2-28", + "334:2-24 -> 334:2-24", + "335:2-25 -> 335:2-25", + "336:2-26 -> 336:2-26", + "337:2-23 -> 337:2-23", + "338:0 -> 338:0", + ] + `) +}) + +test('utilities have source maps', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) +}) + +test('components have source maps', async () => { + let config = { + content: [{ raw: `container` }], + } + + let input = css` + @tailwind components; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-13 -> 2:2-13", + "3:0 -> 3:0", + "2:4 -> 5:0", + "2:4 -> 6:2", + "7:4-20 -> 7:4-20", + "8:2 -> 8:2", + "9:0 -> 9:0", + "2:4 -> 11:0", + "2:4 -> 12:2", + "13:4-20 -> 13:4-20", + "14:2 -> 14:2", + "15:0 -> 15:0", + "2:4 -> 17:0", + "2:4 -> 18:2", + "19:4-21 -> 19:4-21", + "20:2 -> 20:2", + "21:0 -> 21:0", + "2:4 -> 23:0", + "2:4 -> 24:2", + "25:4-21 -> 25:4-21", + "26:2 -> 26:2", + "27:0 -> 27:0", + "2:4 -> 29:0", + "2:4 -> 30:2", + "31:4-21 -> 31:4-21", + "32:2 -> 32:2", + "33:0 -> 33:0", + ] + `) +}) + +test('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { + let config = { + content: [{ raw: `font-normal foo hover:foo` }], + } + + let utilitiesFile = postcss.parse( + css` + @tailwind utilities; + `, + { from: 'components.css', map: { prev: map } } + ) + + let mainCssFile = postcss.parse( + css` + @layer utilities { + .foo { + background-color: red; + } + } + `, + { from: 'input.css', map: { prev: map } } + ) + + // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` + let input = postcss.root({ + nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], + source: mainCssFile.source, + }) + + let result = await run(input, config) + + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + + // And we should see that the source map for the layer rule is not rewritten + // to point to the @tailwind directive but instead points to the original + expect(sources.length).toBe(3) + expect(sources).toMatchInlineSnapshot(` + [ + "components.css", + "source-maps.test.js%3Ftest=c291cmNlIG1hcHMgZm9yIGxheWVyIHJ1bGVzIGFyZSBub3QgcmV3cml0dGVuIHRvIHBvaW50IHRvIEB0YWlsd2luZCBkaXJlY3RpdmVz", + "input.css", + ] + `) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:6 -> 1:0", + "2:2-18 -> 2:2-18", + "3:0 -> 3:0", + "3:8 -> 5:0", + "6:2-23 -> 6:2-23", + "7:0 -> 7:0", + ] + `) +}) + +test('it handles `map: true` correctly', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config, { + map: true, + }) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) +}) + +test('it handles `map: { inline: true }` correctly', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config, { + map: { + inline: true, + }, + }) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) }) diff --git a/tests/space-utilities.test.js b/tests/space-utilities.test.js new file mode 100644 index 000000000..194c63ce2 --- /dev/null +++ b/tests/space-utilities.test.js @@ -0,0 +1,43 @@ +import { run, html, css, defaults } from './util/run' + +test('space-x uses non-logical properties', () => { + let config = { + future: { + logicalSiblingUtilities: false, + }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); + } + `) + }) +}) + +test('space-x uses logical properties', () => { + let config = { + future: { + logicalSiblingUtilities: true, + }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); + margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); + } + `) + }) +}) diff --git a/tests/syntax-lit-html.test.js b/tests/syntax-lit-html.test.js index 952a9b969..a3bdfebda 100644 --- a/tests/syntax-lit-html.test.js +++ b/tests/syntax-lit-html.test.js @@ -1,72 +1,45 @@ -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('it detects classes in lit-html templates', () => { - let config = { - content: [ - { - raw: `html\`\`;`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } +test('it detects classes in lit-html templates', () => { + let config = { + content: [ + { + raw: `html\`\`;`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .rounded { - border-radius: 0.25rem; - } - .bg-blue-400 { - --tw-bg-opacity: 1; - background-color: rgb(96 165 250 / var(--tw-bg-opacity)); - } - .px-4 { - padding-left: 1rem; - padding-right: 1rem; - } - .py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - .font-bold { - font-weight: 700; - } - .text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } - .hover\:bg-blue-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .rounded { - border-radius: 0.25rem; - } - .bg-blue-400 { - background-color: #60a5fa; - } - .px-4 { - padding-left: 1rem; - padding-right: 1rem; - } - .py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - .font-bold { - font-weight: 700; - } - .text-white { - color: #fff; - } - .hover\:bg-blue-600:hover { - background-color: #2563eb; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .rounded { + border-radius: 0.25rem; + } + .bg-blue-400 { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); + } + .px-4 { + padding-left: 1rem; + padding-right: 1rem; + } + .py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + } + .font-bold { + font-weight: 700; + } + .text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + .hover\:bg-blue-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); + } + `) }) }) diff --git a/tests/syntax-svelte.test.js b/tests/syntax-svelte.test.js index be2c33e8b..b6df41f13 100644 --- a/tests/syntax-svelte.test.js +++ b/tests/syntax-svelte.test.js @@ -1,43 +1,40 @@ import path from 'path' -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('it detects svelte based on the file extension') - stable.test('it detects svelte based on the file extension', () => { - let config = { - content: [path.resolve(__dirname, './syntax-svelte.test.svelte')], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } +test('it detects svelte based on the file extension', () => { + let config = { + content: [path.resolve(__dirname, './syntax-svelte.test.svelte')], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .bg-red-500 { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + @media (min-width: 1024px) { + .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { - .lg\:hover\:bg-blue-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - } - } - `) - }) + } + `) }) +}) - oxide.test.todo('using raw with svelte extension') - stable.test('using raw with svelte extension', () => { - let config = { - content: [ - { - raw: ` +test('using raw with svelte extension', () => { + let config = { + content: [ + { + raw: ` @@ -50,32 +47,31 @@ crosscheck(({ stable, oxide }) => { Click me `, - extension: 'svelte', - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } + extension: 'svelte', + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .bg-red-500 { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + @media (min-width: 1024px) { + .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { - .lg\:hover\:bg-blue-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - } - } - `) - }) + } + `) }) }) diff --git a/tests/tailwind-screens.test.js b/tests/tailwind-screens.test.js index f968fd0e3..009c02bc3 100644 --- a/tests/tailwind-screens.test.js +++ b/tests/tailwind-screens.test.js @@ -1,65 +1,63 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('class variants are inserted at `@tailwind variants`', async () => { - let config = { - content: [{ raw: html`
` }], +test('class variants are inserted at `@tailwind variants`', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + @tailwind variants; + .foo { + color: black; } + ` - let input = css` - @tailwind utilities; - @tailwind variants; - .foo { - color: black; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .hover\:font-bold:hover { + font-weight: 700; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold, - .hover\:font-bold:hover { + @media (min-width: 768px) { + .md\:font-bold { font-weight: 700; } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - .foo { - color: #000; - } - `) - }) - }) - - test('`@tailwind screens` works as an alias for `@tailwind variants`', async () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind utilities; - @tailwind screens; - .foo { - color: black; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold, - .hover\:font-bold:hover { - font-weight: 700; - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - .foo { - color: #000; - } - `) - }) + .foo { + color: #000; + } + `) + }) +}) + +test('`@tailwind screens` works as an alias for `@tailwind variants`', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + @tailwind screens; + .foo { + color: black; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .hover\:font-bold:hover { + font-weight: 700; + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + .foo { + color: #000; + } + `) }) }) diff --git a/tests/to-path.test.js b/tests/to-path.test.js index 1e6021ba9..8737194ed 100644 --- a/tests/to-path.test.js +++ b/tests/to-path.test.js @@ -1,21 +1,18 @@ import { toPath } from '../src/util/toPath' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should keep an array as an array', () => { - let input = ['a', 'b', '0', 'c'] +it('should keep an array as an array', () => { + let input = ['a', 'b', '0', 'c'] - expect(toPath(input)).toBe(input) - }) - - it.each` - input | output - ${'a.b.c'} | ${['a', 'b', 'c']} - ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} - ${'.a'} | ${['a']} - ${'[].a'} | ${['a']} - ${'a[1.5][b][c]'} | ${['a', '1.5', 'b', 'c']} - `('should convert "$input" to "$output"', ({ input, output }) => { - expect(toPath(input)).toEqual(output) - }) + expect(toPath(input)).toBe(input) +}) + +it.each` + input | output + ${'a.b.c'} | ${['a', 'b', 'c']} + ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} + ${'.a'} | ${['a']} + ${'[].a'} | ${['a']} + ${'a[1.5][b][c]'} | ${['a', '1.5', 'b', 'c']} +`('should convert "$input" to "$output"', ({ input, output }) => { + expect(toPath(input)).toEqual(output) }) diff --git a/tests/util/apply-important-selector.test.js b/tests/util/apply-important-selector.test.js index 0ec22792f..0622d802e 100644 --- a/tests/util/apply-important-selector.test.js +++ b/tests/util/apply-important-selector.test.js @@ -1,24 +1,25 @@ -import { crosscheck } from '../util/run' import { applyImportantSelector } from '../../src/util/applyImportantSelector' -crosscheck(() => { - it.each` - before | after - ${'.foo'} | ${'#app :is(.foo)'} - ${'.foo .bar'} | ${'#app :is(.foo .bar)'} - ${'.foo:hover'} | ${'#app :is(.foo:hover)'} - ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} - ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} - ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} - ${':is(.dark :is([dir="rtl"] .foo::before))'} | ${'#app :is(.dark :is([dir="rtl"] .foo))::before'} - ${':is(.dark .foo) .bar'} | ${'#app :is(:is(.dark .foo) .bar)'} - ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} - ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} - ${'.foo:before'} | ${'#app :is(.foo):before'} - `('should generate "$after" from "$before"', ({ before, after }) => { - expect(applyImportantSelector(before, '#app')).toEqual(after) - }) +it.each` + before | after + ${'.foo'} | ${'#app :is(.foo)'} + ${'.foo .bar'} | ${'#app :is(.foo .bar)'} + ${'.foo:hover'} | ${'#app :is(.foo:hover)'} + ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} + ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} + ${':is(.dark :is([dir="rtl"] .foo::before))'} | ${'#app :is(.dark :is([dir="rtl"] .foo))::before'} + ${':is(.dark .foo) .bar'} | ${'#app :is(:is(.dark .foo) .bar)'} + ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} + ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} + ${'.foo:before'} | ${'#app :is(.foo):before'} + ${'.foo::some-uknown-pseudo'} | ${'#app :is(.foo)::some-uknown-pseudo'} + ${'.foo::some-uknown-pseudo:hover'} | ${'#app :is(.foo)::some-uknown-pseudo:hover'} + ${'.foo:focus::some-uknown-pseudo:hover'} | ${'#app :is(.foo:focus)::some-uknown-pseudo:hover'} + ${'.foo:hover::some-uknown-pseudo:focus'} | ${'#app :is(.foo:hover)::some-uknown-pseudo:focus'} +`('should generate "$after" from "$before"', ({ before, after }) => { + expect(applyImportantSelector(before, '#app')).toEqual(after) }) diff --git a/tests/util/crosscheck.test.js b/tests/util/crosscheck.test.js deleted file mode 100644 index 032473386..000000000 --- a/tests/util/crosscheck.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import { crosscheck } from './run' - -crosscheck(({ stable, oxide, engine }) => { - stable.test('should run on stable', () => { - expect(engine.stable).toBe(true) - expect(engine.oxide).toBe(false) - }) - oxide.test('should run on oxide', () => { - expect(engine.stable).toBe(false) - expect(engine.oxide).toBe(true) - }) - test('should run on both', () => { - oxide.expect(engine.oxide).toBe(true) - oxide.expect(engine.stable).toBe(false) - stable.expect(engine.oxide).toBe(false) - stable.expect(engine.stable).toBe(true) - }) -}) diff --git a/tests/util/defaults.js b/tests/util/defaults.js index bea97d338..77749244c 100644 --- a/tests/util/defaults.js +++ b/tests/util/defaults.js @@ -9,7 +9,106 @@ export function defaults({ defaultRingColor = `#3b82f680` } = {}) { return css` *, :before, - :after, + :after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: ${defaultRingColor}; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + } + + ::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: ${defaultRingColor}; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + } + ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; diff --git a/tests/util/run.js b/tests/util/run.js index 118edcb75..12594ec18 100644 --- a/tests/util/run.js +++ b/tests/util/run.js @@ -1,7 +1,5 @@ -import path from 'path' import postcss from 'postcss' import tailwind from '../../src' -import { env } from '../../src/lib/sharedState' export * from './strings' export * from './defaults' @@ -14,81 +12,28 @@ export let map = JSON.stringify({ mappings: '', }) -globalThis.__OXIDE__ = env.ENGINE === 'oxide' - export function run(input, config, plugin = tailwind) { - let { currentTestName } = expect.getState() + let { currentTestName, testPath } = expect.getState() + let path = `${testPath}?test=${Buffer.from(currentTestName).toString('base64')}` return postcss(plugin(config)).process(input, { - from: `${path.resolve(__filename)}?test=${currentTestName}`, + from: path, + to: path, }) } -export function runWithSourceMaps(input, config, plugin = tailwind) { - let { currentTestName } = expect.getState() +export function runWithSourceMaps( + input, + config, + options = { map: { prev: map } }, + plugin = tailwind +) { + let { currentTestName, testPath } = expect.getState() + let path = `${testPath}?test=${Buffer.from(currentTestName).toString('base64')}` return postcss(plugin(config)).process(input, { - from: `${path.resolve(__filename)}?test=${currentTestName}`, - map: { - prev: map, - }, - }) -} - -let nullTest = Object.assign(function () {}, { - skip: () => {}, - only: () => {}, - each: () => () => {}, - todo: () => {}, -}) -let nullProxy = new Proxy( - { - test: nullTest, - it: nullTest, - xit: nullTest.skip, - fit: nullTest.only, - xdescribe: nullTest.skip, - fdescribe: nullTest.only, - }, - { - get(target, prop, _receiver) { - if (prop in target) { - return target[prop] - } - return Object.assign(() => { - return nullProxy - }, nullProxy) - }, - } -) - -/** - * @typedef {object} CrossCheck - * @property {typeof import('@jest/globals')} oxide - * @property {typeof import('@jest/globals')} stable - * @property {object} engine - * @property {boolean} engine.oxide - * @property {boolean} engine.stable - */ - -/** - * @param {(data: CrossCheck) => void} fn - */ -export function crosscheck(fn) { - let engines = - env.ENGINE === 'oxide' ? [{ engine: 'Stable' }, { engine: 'Oxide' }] : [{ engine: 'Stable' }] - - describe.each(engines)('$engine', ({ engine }) => { - let engines = { - oxide: engine === 'Oxide' ? globalThis : nullProxy, - stable: engine === 'Stable' ? globalThis : nullProxy, - engine: { oxide: engine === 'Oxide', stable: engine === 'Stable' }, - } - - beforeEach(() => { - globalThis.__OXIDE__ = engines.engine.oxide - }) - - fn(engines) + from: path, + to: path, + ...options, }) } diff --git a/tests/util/source-maps.js b/tests/util/source-maps.js index 4ed263126..fe460d844 100644 --- a/tests/util/source-maps.js +++ b/tests/util/source-maps.js @@ -6,7 +6,16 @@ import { SourceMapConsumer } from 'source-map-js' * @param {import('postcss').Result} result */ export function parseSourceMaps(result) { - let map = result.map.toJSON() + let map = result.map + ? result.map.toJSON() + : (() => { + let css = result.toString() + let sourceMappingURL = css.match(/\/\*# sourceMappingURL=(.*) \*\//)?.[1] + let raw = sourceMappingURL + ? Buffer.from(sourceMappingURL.split(',')[1], 'base64').toString() + : null + return JSON.parse(raw ?? '{}') + })() return { sources: map.sources, @@ -15,7 +24,7 @@ export function parseSourceMaps(result) { } /** - * An string annotation that represents a source map + * A string annotation that represents a source map * * It's not meant to be exhaustive just enough to * verify that the source map is working and that diff --git a/tests/variants.oxide.test.css b/tests/variants.oxide.test.css deleted file mode 100644 index 5e06f3942..000000000 --- a/tests/variants.oxide.test.css +++ /dev/null @@ -1,412 +0,0 @@ -*, -:before, -:after, -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.first-letter\:text-2xl:first-letter { - font-size: 1.5rem; - line-height: 2rem; -} -.first-letter\:text-red-500:first-letter { - color: #ef4444; -} -.first-line\:bg-yellow-300:first-line { - background-color: #fde047; -} -.first-line\:underline:first-line { - text-decoration-line: underline; -} -.marker\:text-lg ::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500 ::marker { - color: #ef4444; -} -.marker\:text-lg::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500::marker { - color: #ef4444; -} -.selection\:bg-blue-500 ::selection { - background-color: #3b82f6; -} -.selection\:text-white ::selection { - color: #fff; -} -.selection\:bg-blue-500::selection { - background-color: #3b82f6; -} -.selection\:text-white::selection { - color: #fff; -} -.file\:bg-blue-500::file-selector-button { - background-color: #3b82f6; -} -.file\:text-white::file-selector-button { - color: #fff; -} -.placeholder\:font-bold::placeholder { - font-weight: 700; -} -.placeholder\:text-red-500::placeholder { - color: #ef4444; -} -.backdrop\:shadow-md::backdrop { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.before\:block:before { - content: var(--tw-content); - display: block; -} -.before\:bg-red-500:before { - content: var(--tw-content); - background-color: #ef4444; -} -.after\:flex:after { - content: var(--tw-content); - display: flex; -} -.after\:uppercase:after { - content: var(--tw-content); - text-transform: uppercase; -} -.first\:shadow-md:first-child, -.last\:shadow-md:last-child, -.only\:shadow-md:only-child, -.odd\:shadow-md:nth-child(2n + 1), -.even\:shadow-md:nth-child(2n), -.first-of-type\:shadow-md:first-of-type, -.last-of-type\:shadow-md:last-of-type, -.only-of-type\:shadow-md:only-of-type, -.visited\:shadow-md:visited, -.target\:shadow-md:target { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.open\:bg-red-200[open] { - background-color: #fecaca; -} -.default\:shadow-md:default, -.checked\:shadow-md:checked, -.indeterminate\:shadow-md:indeterminate, -.placeholder-shown\:shadow-md:placeholder-shown, -.autofill\:shadow-md:autofill, -.optional\:shadow-md:optional, -.required\:shadow-md:required, -.valid\:shadow-md:valid, -.invalid\:shadow-md:invalid, -.in-range\:shadow-md:in-range, -.out-of-range\:shadow-md:out-of-range, -.read-only\:shadow-md:read-only, -.empty\:shadow-md:empty, -.focus-within\:shadow-md:focus-within { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.hover\:animate-spin:hover { - animation: 1s linear infinite spin; -} -.hover\:shadow-md:hover { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.file\:hover\:bg-blue-600:hover::file-selector-button { - background-color: #2563eb; -} -.open\:hover\:bg-red-200:hover[open] { - background-color: #fecaca; -} -.focus\:shadow-md:focus, -.focus\:hover\:shadow-md:hover:focus, -.focus-visible\:shadow-md:focus-visible, -.active\:shadow-md:active, -.enabled\:shadow-md:enabled, -.disabled\:shadow-md:disabled, -.group:first-child .group-first\:shadow-md, -.group:last-child .group-last\:shadow-md, -.group:only-child .group-only\:shadow-md, -.group:nth-child(2n + 1) .group-odd\:shadow-md, -.group:nth-child(2n) .group-even\:shadow-md, -.group:first-of-type .group-first-of-type\:shadow-md, -.group:last-of-type .group-last-of-type\:shadow-md, -.group:only-of-type .group-only-of-type\:shadow-md, -.group:visited .group-visited\:shadow-md, -.group:target .group-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open] .group-open\:bg-red-200 { - background-color: #fecaca; -} -.group:default .group-default\:shadow-md, -.group:checked .group-checked\:shadow-md, -.group:indeterminate .group-indeterminate\:shadow-md, -.group:placeholder-shown .group-placeholder-shown\:shadow-md, -.group:autofill .group-autofill\:shadow-md, -.group:optional .group-optional\:shadow-md, -.group:required .group-required\:shadow-md, -.group:valid .group-valid\:shadow-md, -.group:invalid .group-invalid\:shadow-md, -.group:in-range .group-in-range\:shadow-md, -.group:out-of-range .group-out-of-range\:shadow-md, -.group:read-only .group-read-only\:shadow-md, -.group:empty .group-empty\:shadow-md, -.group:focus-within .group-focus-within\:shadow-md, -.group:hover .group-hover\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:hover .group-open\:group-hover\:space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(0.5rem * var(--tw-space-x-reverse)); -} -.group:focus .group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:focus .group-open\:group-focus\:bg-red-200 { - background-color: #fecaca; -} -.group:focus:hover .group-focus\:group-hover\:shadow-md, -.group:focus-visible .group-focus-visible\:shadow-md, -.group:active .group-active\:shadow-md, -.group:enabled .group-enabled\:shadow-md, -.group:disabled .group-disabled\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:shadow-md:first-child, -.peer:first-child ~ .peer-first\:shadow-md, -.peer:last-child ~ .peer-last\:shadow-md, -.peer:only-child ~ .peer-only\:shadow-md, -.peer:nth-child(2n + 1) ~ .peer-odd\:shadow-md, -.peer:nth-child(2n) ~ .peer-even\:shadow-md, -.peer:first-of-type ~ .peer-first-of-type\:shadow-md, -.peer:last-of-type ~ .peer-last-of-type\:shadow-md, -.peer:only-of-type ~ .peer-only-of-type\:shadow-md, -.peer:visited ~ .peer-visited\:shadow-md, -.peer:target ~ .peer-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.peer[open] ~ .peer-open\:bg-red-200 { - background-color: #fecaca; -} -.peer:default ~ .peer-default\:shadow-md, -.peer:checked ~ .peer-checked\:shadow-md, -.peer:indeterminate ~ .peer-indeterminate\:shadow-md, -.peer:placeholder-shown ~ .peer-placeholder-shown\:shadow-md, -.peer:autofill ~ .peer-autofill\:shadow-md, -.peer:optional ~ .peer-optional\:shadow-md, -.peer:required ~ .peer-required\:shadow-md, -.peer:valid ~ .peer-valid\:shadow-md, -.peer:invalid ~ .peer-invalid\:shadow-md, -.peer:in-range ~ .peer-in-range\:shadow-md, -.peer:out-of-range ~ .peer-out-of-range\:shadow-md, -.peer:read-only ~ .peer-read-only\:shadow-md, -.peer:empty ~ .peer-empty\:shadow-md, -.peer:focus-within ~ .peer-focus-within\:shadow-md, -.peer:hover ~ .peer-hover\:shadow-md, -.peer:focus ~ .peer-focus\:shadow-md, -.peer:focus:hover ~ .peer-focus\:peer-hover\:shadow-md, -.peer:focus-visible ~ .peer-focus-visible\:shadow-md, -.peer:active ~ .peer-active\:shadow-md, -.peer:enabled ~ .peer-enabled\:shadow-md, -.peer:disabled ~ .peer-disabled\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -:is([dir='ltr'] .ltr\:shadow-md), -:is([dir='rtl'] .rtl\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@media (prefers-reduced-motion: no-preference) { - .motion-safe\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (prefers-reduced-motion: reduce) { - .motion-reduce\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (prefers-contrast: more) { - .contrast-more\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (prefers-contrast: less) { - .contrast-less\:bg-yellow-300 { - background-color: #fde047; - } -} -:is(.dark .dark\:shadow-md), -:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), -:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@media print { - .print\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (min-width: 640px) { - .sm\:shadow-md, - .sm\:active\:shadow-md:active { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 768px) { - .md\:shadow-md, - .group:focus .md\:group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1024px) { - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .lg\:animate-spin { - animation: 1s linear infinite spin; - } - .lg\:shadow-md, - :is(.dark .lg\:dark\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1280px) { - .xl\:shadow-md, - :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1536px) { - .\32 xl\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - @media (prefers-reduced-motion: no-preference) { - :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - } -} -@media (orientation: portrait) { - .portrait\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (orientation: landscape) { - .landscape\:bg-yellow-300 { - background-color: #fde047; - } -} diff --git a/tests/variants.test.css b/tests/variants.test.css index 8a9d481ee..22fc0691d 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -1,6 +1,103 @@ *, :before, -:after, +:after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; @@ -50,384 +147,316 @@ --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; } -.first-letter\:text-2xl:first-letter { - font-size: 1.5rem; - line-height: 2rem; +.first-letter\:flex:first-letter, +.first-line\:flex:first-line { + display: flex; } -.first-letter\:text-red-500:first-letter { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); +.marker\:flex ::marker { + display: flex; } -.first-line\:bg-yellow-300:first-line { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); +.marker\:flex::marker { + display: flex; } -.first-line\:underline:first-line { - text-decoration-line: underline; +.selection\:flex ::selection { + display: flex; } -.marker\:text-lg ::marker { - font-size: 1.125rem; - line-height: 1.75rem; +.selection\:flex::selection { + display: flex; } -.marker\:text-red-500 ::marker { - color: #ef4444; +.file\:flex::-webkit-file-upload-button { + display: flex; } -.marker\:text-lg::marker { - font-size: 1.125rem; - line-height: 1.75rem; +.file\:flex::file-selector-button { + display: flex; } -.marker\:text-red-500::marker { - color: #ef4444; +.placeholder\:flex::placeholder { + display: flex; } -.selection\:bg-blue-500 ::selection { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +.backdrop\:flex::-webkit-backdrop { + display: flex; } -.selection\:text-white ::selection { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.selection\:bg-blue-500::selection { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} -.selection\:text-white::selection { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.file\:bg-blue-500::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} -.file\:text-white::file-selector-button { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.placeholder\:font-bold::placeholder { - font-weight: 700; -} -.placeholder\:text-red-500::placeholder { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); -} -.backdrop\:shadow-md::backdrop { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.before\:block:before { - content: var(--tw-content); - display: block; -} -.before\:bg-red-500:before { - content: var(--tw-content); - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); +.backdrop\:flex::backdrop { + display: flex; } +.before\:flex:before, .after\:flex:after { content: var(--tw-content); display: flex; } -.after\:uppercase:after { - content: var(--tw-content); - text-transform: uppercase; +.first\:flex:first-child, +.last\:flex:last-child, +.only\:flex:only-child, +.odd\:flex:nth-child(odd), +.even\:flex:nth-child(2n), +.first-of-type\:flex:first-of-type, +.last-of-type\:flex:last-of-type, +.only-of-type\:flex:only-of-type, +.visited\:flex:visited, +.target\:flex:target, +.open\:flex[open], +.default\:flex:default, +.checked\:flex:checked, +.indeterminate\:flex:indeterminate, +.placeholder-shown\:flex:placeholder-shown { + display: flex; } -.first\:shadow-md:first-child, -.last\:shadow-md:last-child, -.only\:shadow-md:only-child, -.odd\:shadow-md:nth-child(2n + 1), -.even\:shadow-md:nth-child(2n), -.first-of-type\:shadow-md:first-of-type, -.last-of-type\:shadow-md:last-of-type, -.only-of-type\:shadow-md:only-of-type, -.visited\:shadow-md:visited, -.target\:shadow-md:target { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.autofill\:flex:-webkit-autofill { + display: flex; } -.open\:bg-red-200[open] { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +.autofill\:flex:autofill { + display: flex; } -.default\:shadow-md:default, -.checked\:shadow-md:checked, -.indeterminate\:shadow-md:indeterminate, -.placeholder-shown\:shadow-md:placeholder-shown, -.autofill\:shadow-md:autofill, -.optional\:shadow-md:optional, -.required\:shadow-md:required, -.valid\:shadow-md:valid, -.invalid\:shadow-md:invalid, -.in-range\:shadow-md:in-range, -.out-of-range\:shadow-md:out-of-range, -.read-only\:shadow-md:read-only, -.empty\:shadow-md:empty, -.focus-within\:shadow-md:focus-within { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.optional\:flex:optional, +.required\:flex:required, +.valid\:flex:valid, +.invalid\:flex:invalid, +.in-range\:flex:in-range, +.out-of-range\:flex:out-of-range, +.read-only\:flex:read-only, +.empty\:flex:empty, +.focus-within\:flex:focus-within, +.hover\:flex:hover { + display: flex; } -@keyframes spin { - to { - transform: rotate(360deg); - } +.file\:hover\:flex:hover::-webkit-file-upload-button { + display: flex; } -.hover\:animate-spin:hover { - animation: 1s linear infinite spin; +.file\:hover\:flex:hover::file-selector-button { + display: flex; } -.hover\:shadow-md:hover { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.open\:hover\:flex:hover[open], +.focus\:flex:focus, +.focus\:hover\:flex:hover:focus { + display: flex; } -.file\:hover\:bg-blue-600:hover::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +.focus-visible\:flex:focus-visible { + display: flex; } -.open\:hover\:bg-red-200:hover[open] { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); +.active\:flex:active, +.enabled\:flex:enabled, +.disabled\:flex:disabled, +.group:first-child .group-first\:flex, +.group:last-child .group-last\:flex, +.group:only-child .group-only\:flex, +.group:nth-child(odd) .group-odd\:flex, +.group:nth-child(2n) .group-even\:flex, +.group:first-of-type .group-first-of-type\:flex, +.group:last-of-type .group-last-of-type\:flex, +.group:only-of-type .group-only-of-type\:flex, +.group:visited .group-visited\:flex, +.group:target .group-target\:flex, +.group[open] .group-open\:flex, +.group:default .group-default\:flex, +.group:checked .group-checked\:flex, +.group:indeterminate .group-indeterminate\:flex, +.group:placeholder-shown .group-placeholder-shown\:flex, +.group:-webkit-autofill .group-autofill\:flex, +.group:optional .group-optional\:flex, +.group:required .group-required\:flex, +.group:valid .group-valid\:flex, +.group:invalid .group-invalid\:flex, +.group:in-range .group-in-range\:flex, +.group:out-of-range .group-out-of-range\:flex, +.group:read-only .group-read-only\:flex, +.group:empty .group-empty\:flex, +.group:focus-within .group-focus-within\:flex, +.group:hover .group-hover\:flex, +.group[open]:hover .group-open\:group-hover\:flex, +.group:focus .group-focus\:flex, +.group[open]:focus .group-open\:group-focus\:flex, +.group:focus:hover .group-focus\:group-hover\:flex, +.group:focus-visible .group-focus-visible\:flex, +.group:active .group-active\:flex, +.group:enabled .group-enabled\:flex, +.group:disabled .group-disabled\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:flex:first-child, +.peer:first-child ~ .peer-first\:flex, +.peer:last-child ~ .peer-last\:flex, +.peer:only-child ~ .peer-only\:flex, +.peer:nth-child(odd) ~ .peer-odd\:flex, +.peer:nth-child(2n) ~ .peer-even\:flex, +.peer:first-of-type ~ .peer-first-of-type\:flex, +.peer:last-of-type ~ .peer-last-of-type\:flex, +.peer:only-of-type ~ .peer-only-of-type\:flex, +.peer:visited ~ .peer-visited\:flex, +.peer:target ~ .peer-target\:flex, +.peer[open] ~ .peer-open\:flex, +.peer:default ~ .peer-default\:flex, +.peer:checked ~ .peer-checked\:flex, +.peer:indeterminate ~ .peer-indeterminate\:flex, +.peer:placeholder-shown ~ .peer-placeholder-shown\:flex, +.peer:-webkit-autofill ~ .peer-autofill\:flex, +.peer:optional ~ .peer-optional\:flex, +.peer:required ~ .peer-required\:flex, +.peer:valid ~ .peer-valid\:flex, +.peer:invalid ~ .peer-invalid\:flex, +.peer:in-range ~ .peer-in-range\:flex, +.peer:out-of-range ~ .peer-out-of-range\:flex, +.peer:read-only ~ .peer-read-only\:flex, +.peer:empty ~ .peer-empty\:flex, +.peer:focus-within ~ .peer-focus-within\:flex, +.peer:hover ~ .peer-hover\:flex, +.peer:focus ~ .peer-focus\:flex, +.peer:focus:hover ~ .peer-focus\:peer-hover\:flex, +.peer:focus-visible ~ .peer-focus-visible\:flex, +.peer:active ~ .peer-active\:flex, +.peer:enabled ~ .peer-enabled\:flex, +.peer:disabled ~ .peer-disabled\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child, +:-webkit-any([dir='ltr'] .ltr\:flex), +:-webkit-any([dir='rtl'] .rtl\:flex) { + display: flex; } -.focus\:shadow-md:focus, -.focus\:hover\:shadow-md:hover:focus, -.focus-visible\:shadow-md:focus-visible, -.active\:shadow-md:active, -.enabled\:shadow-md:enabled, -.disabled\:shadow-md:disabled, -.group:first-child .group-first\:shadow-md, -.group:last-child .group-last\:shadow-md, -.group:only-child .group-only\:shadow-md, -.group:nth-child(2n + 1) .group-odd\:shadow-md, -.group:nth-child(2n) .group-even\:shadow-md, -.group:first-of-type .group-first-of-type\:shadow-md, -.group:last-of-type .group-last-of-type\:shadow-md, -.group:only-of-type .group-only-of-type\:shadow-md, -.group:visited .group-visited\:shadow-md, -.group:target .group-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open] .group-open\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.group:default .group-default\:shadow-md, -.group:checked .group-checked\:shadow-md, -.group:indeterminate .group-indeterminate\:shadow-md, -.group:placeholder-shown .group-placeholder-shown\:shadow-md, -.group:autofill .group-autofill\:shadow-md, -.group:optional .group-optional\:shadow-md, -.group:required .group-required\:shadow-md, -.group:valid .group-valid\:shadow-md, -.group:invalid .group-invalid\:shadow-md, -.group:in-range .group-in-range\:shadow-md, -.group:out-of-range .group-out-of-range\:shadow-md, -.group:read-only .group-read-only\:shadow-md, -.group:empty .group-empty\:shadow-md, -.group:focus-within .group-focus-within\:shadow-md, -.group:hover .group-hover\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:hover .group-open\:group-hover\:space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.5rem * var(--tw-space-x-reverse)); - margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); -} -.group:focus .group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:focus .group-open\:group-focus\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.group:focus:hover .group-focus\:group-hover\:shadow-md, -.group:focus-visible .group-focus-visible\:shadow-md, -.group:active .group-active\:shadow-md, -.group:enabled .group-enabled\:shadow-md, -.group:disabled .group-disabled\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:shadow-md:first-child, -.peer:first-child ~ .peer-first\:shadow-md, -.peer:last-child ~ .peer-last\:shadow-md, -.peer:only-child ~ .peer-only\:shadow-md, -.peer:nth-child(2n + 1) ~ .peer-odd\:shadow-md, -.peer:nth-child(2n) ~ .peer-even\:shadow-md, -.peer:first-of-type ~ .peer-first-of-type\:shadow-md, -.peer:last-of-type ~ .peer-last-of-type\:shadow-md, -.peer:only-of-type ~ .peer-only-of-type\:shadow-md, -.peer:visited ~ .peer-visited\:shadow-md, -.peer:target ~ .peer-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.peer[open] ~ .peer-open\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.peer:default ~ .peer-default\:shadow-md, -.peer:checked ~ .peer-checked\:shadow-md, -.peer:indeterminate ~ .peer-indeterminate\:shadow-md, -.peer:placeholder-shown ~ .peer-placeholder-shown\:shadow-md, -.peer:autofill ~ .peer-autofill\:shadow-md, -.peer:optional ~ .peer-optional\:shadow-md, -.peer:required ~ .peer-required\:shadow-md, -.peer:valid ~ .peer-valid\:shadow-md, -.peer:invalid ~ .peer-invalid\:shadow-md, -.peer:in-range ~ .peer-in-range\:shadow-md, -.peer:out-of-range ~ .peer-out-of-range\:shadow-md, -.peer:read-only ~ .peer-read-only\:shadow-md, -.peer:empty ~ .peer-empty\:shadow-md, -.peer:focus-within ~ .peer-focus-within\:shadow-md, -.peer:hover ~ .peer-hover\:shadow-md, -.peer:focus ~ .peer-focus\:shadow-md, -.peer:focus:hover ~ .peer-focus\:peer-hover\:shadow-md, -.peer:focus-visible ~ .peer-focus-visible\:shadow-md, -.peer:active ~ .peer-active\:shadow-md, -.peer:enabled ~ .peer-enabled\:shadow-md, -.peer:disabled ~ .peer-disabled\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -:is([dir='ltr'] .ltr\:shadow-md), -:is([dir='rtl'] .rtl\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.active\:flex:active, +.enabled\:flex:enabled, +.disabled\:flex:disabled, +.group:first-child .group-first\:flex, +.group:last-child .group-last\:flex, +.group:only-child .group-only\:flex, +.group:nth-child(odd) .group-odd\:flex, +.group:nth-child(2n) .group-even\:flex, +.group:first-of-type .group-first-of-type\:flex, +.group:last-of-type .group-last-of-type\:flex, +.group:only-of-type .group-only-of-type\:flex, +.group:visited .group-visited\:flex, +.group:target .group-target\:flex, +.group[open] .group-open\:flex, +.group:default .group-default\:flex, +.group:checked .group-checked\:flex, +.group:indeterminate .group-indeterminate\:flex, +.group:placeholder-shown .group-placeholder-shown\:flex, +.group:autofill .group-autofill\:flex, +.group:optional .group-optional\:flex, +.group:required .group-required\:flex, +.group:valid .group-valid\:flex, +.group:invalid .group-invalid\:flex, +.group:in-range .group-in-range\:flex, +.group:out-of-range .group-out-of-range\:flex, +.group:read-only .group-read-only\:flex, +.group:empty .group-empty\:flex, +.group:focus-within .group-focus-within\:flex, +.group:hover .group-hover\:flex, +.group[open]:hover .group-open\:group-hover\:flex, +.group:focus .group-focus\:flex, +.group[open]:focus .group-open\:group-focus\:flex, +.group:focus:hover .group-focus\:group-hover\:flex, +.group:focus-visible .group-focus-visible\:flex, +.group:active .group-active\:flex, +.group:enabled .group-enabled\:flex, +.group:disabled .group-disabled\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:flex:first-child, +.peer:first-child ~ .peer-first\:flex, +.peer:last-child ~ .peer-last\:flex, +.peer:only-child ~ .peer-only\:flex, +.peer:nth-child(odd) ~ .peer-odd\:flex, +.peer:nth-child(2n) ~ .peer-even\:flex, +.peer:first-of-type ~ .peer-first-of-type\:flex, +.peer:last-of-type ~ .peer-last-of-type\:flex, +.peer:only-of-type ~ .peer-only-of-type\:flex, +.peer:visited ~ .peer-visited\:flex, +.peer:target ~ .peer-target\:flex, +.peer[open] ~ .peer-open\:flex, +.peer:default ~ .peer-default\:flex, +.peer:checked ~ .peer-checked\:flex, +.peer:indeterminate ~ .peer-indeterminate\:flex, +.peer:placeholder-shown ~ .peer-placeholder-shown\:flex, +.peer:autofill ~ .peer-autofill\:flex, +.peer:optional ~ .peer-optional\:flex, +.peer:required ~ .peer-required\:flex, +.peer:valid ~ .peer-valid\:flex, +.peer:invalid ~ .peer-invalid\:flex, +.peer:in-range ~ .peer-in-range\:flex, +.peer:out-of-range ~ .peer-out-of-range\:flex, +.peer:read-only ~ .peer-read-only\:flex, +.peer:empty ~ .peer-empty\:flex, +.peer:focus-within ~ .peer-focus-within\:flex, +.peer:hover ~ .peer-hover\:flex, +.peer:focus ~ .peer-focus\:flex, +.peer:focus:hover ~ .peer-focus\:peer-hover\:flex, +.peer:focus-visible ~ .peer-focus-visible\:flex, +.peer:active ~ .peer-active\:flex, +.peer:enabled ~ .peer-enabled\:flex, +.peer:disabled ~ .peer-disabled\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child, +:is([dir='ltr'] .ltr\:flex), +:is([dir='rtl'] .rtl\:flex) { + display: flex; } @media (prefers-reduced-motion: no-preference) { - .motion-safe\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .motion-safe\:flex { + display: flex; } } @media (prefers-reduced-motion: reduce) { - .motion-reduce\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .motion-reduce\:flex { + display: flex; } } @media (prefers-contrast: more) { - .contrast-more\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .contrast-more\:flex { + display: flex; } } @media (prefers-contrast: less) { - .contrast-less\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .contrast-less\:flex { + display: flex; } } -:is(.dark .dark\:shadow-md), -:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), -:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +:is(.dark .dark\:flex), +:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:flex), +:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:flex) { + display: flex; } @media print { - .print\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .print\:flex { + display: flex; } } @media (min-width: 640px) { - .sm\:shadow-md, - .sm\:active\:shadow-md:active { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .sm\:flex, + .sm\:active\:flex:active { + display: flex; } } @media (min-width: 768px) { - .md\:shadow-md, - .group:focus .md\:group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .md\:flex, + .group:focus .md\:group-focus\:flex { + display: flex; } } @media (min-width: 1024px) { - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .lg\:animate-spin { - animation: 1s linear infinite spin; - } - .lg\:shadow-md, - :is(.dark .lg\:dark\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .lg\:flex, + :is(.dark .lg\:dark\:flex) { + display: flex; } } @media (min-width: 1280px) { - .xl\:shadow-md, - :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .xl\:flex, + :is(.dark .xl\:dark\:disabled\:flex:disabled) { + display: flex; } } @media (min-width: 1536px) { - .\32 xl\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .\32 xl\:flex { + display: flex; } @media (prefers-reduced-motion: no-preference) { - :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:flex:focus-within) { + display: flex; } } } @media (orientation: portrait) { - .portrait\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .portrait\:flex { + display: flex; } } @media (orientation: landscape) { - .landscape\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .landscape\:flex { + display: flex; } } diff --git a/tests/variants.test.html b/tests/variants.test.html index bd40b625f..a9b2c2f16 100644 --- a/tests/variants.test.html +++ b/tests/variants.test.html @@ -1,166 +1,166 @@ -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
    -
  • +
-
-
-
-
-
- +
+
+
+
+
+ -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/tests/variants.test.js b/tests/variants.test.js index da62419d4..f2a2de075 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -1,414 +1,89 @@ import fs from 'fs' import path from 'path' import postcss from 'postcss' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('variants', () => { - let config = { - darkMode: 'class', - content: [path.resolve(__dirname, './variants.test.html')], - corePlugins: { preflight: false }, - } +test('variants', () => { + let config = { + darkMode: 'class', + content: [path.resolve(__dirname, './variants.test.html')], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './variants.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './variants.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './variants.test.css'), 'utf8') + ) }) +}) - test('order matters and produces different behaviour', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - } +test('order matters and produces different behaviour', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .file\:hover\:bg-pink-600:hover::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(219 39 119 / var(--tw-bg-opacity)); - } - .hover\:file\:bg-pink-600::file-selector-button:hover { - --tw-bg-opacity: 1; - background-color: rgb(219 39 119 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .file\:hover\:bg-pink-600:hover::file-selector-button { - background-color: #db2777; - } - .hover\:file\:bg-pink-600::file-selector-button:hover { - background-color: #db2777; - } - `) - }) - }) - - describe('custom advanced variants', () => { - test('prose-headings usage on its own', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :where(.prose-headings\:text-center) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('prose-headings with another "simple" variant', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :where(.hover\:prose-headings\:text-center) :is(h1, h2, h3, h4):hover, - :where(.prose-headings\:hover\:text-center:hover) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('prose-headings with another "complex" variant', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .group:hover :where(.group-hover\:prose-headings\:text-center) :is(h1, h2, h3, h4), - :where(.group:hover .prose-headings\:group-hover\:text-center) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('using variants with multi-class selectors', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant, addComponents }) { - addComponents({ - '.parent .child': { - foo: 'bar', - }, - }) - addVariant('screen', '@media screen') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media screen { - .screen\:parent .child, - .parent .screen\:child { - foo: bar; - } - } - `) - }) - }) - - test('using multiple classNames in your custom variant', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('my-variant', '&:where(.one, .two, .three)') - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .test { - @apply my-variant:italic; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .test:where(.one, .two, .three) { - font-style: italic; - } - .my-variant\:underline:where(.one, .two, .three) { - text-decoration-line: underline; - } - `) - }) - }) - - test('variant format string must include at-rule or & (1)', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('wtf-bbq', 'lol') - }, - ], - } - - await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( - "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." - ) - }) - - test('variant format string must include at-rule or & (2)', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('wtf-bbq', () => 'lol') - }, - ], - } - - await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( - "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." - ) - }) - }) - - test('stacked peer variants', async () => { - let config = { - content: [{ raw: 'peer-disabled:peer-focus:peer-hover:border-blue-500' }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - let result = await run(input, config) - stable.expect(result.css).toIncludeCss(css` - .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:border-blue-500 { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); - } - `) - oxide.expect(result.css).toIncludeCss(css` - .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:border-blue-500 { - border-color: #3b82f6; - } - `) - }) - - it('should properly handle keyframes with multiple variants', async () => { - let config = { - content: [ - { - raw: 'animate-spin hover:animate-spin focus:animate-spin hover:animate-bounce focus:animate-bounce', - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - ` - - let result = await run(input, config) + return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @keyframes spin { - to { - transform: rotate(360deg); - } + .file\:hover\:\[--value\:2\]:hover::-webkit-file-upload-button { + --value: 2; } - .animate-spin { - animation: 1s linear infinite spin; + .file\:hover\:\[--value\:2\]:hover::file-selector-button { + --value: 2; } - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } + .hover\:file\:\[--value\:1\]::-webkit-file-upload-button:hover { + --value: 1; } - .hover\:animate-bounce:hover { - animation: 1s infinite bounce; - } - .hover\:animate-spin:hover { - animation: 1s linear infinite spin; - } - .focus\:animate-bounce:focus { - animation: 1s infinite bounce; - } - .focus\:animate-spin:focus { - animation: 1s linear infinite spin; + .hover\:file\:\[--value\:1\]::file-selector-button:hover { + --value: 1; } `) }) +}) - test('custom addVariant with more complex media query params', () => { +describe('custom advanced variants', () => { + test('prose-headings usage on its own', () => { let config = { content: [ { - raw: html`
`, + raw: html`
`, }, ], plugins: [ function ({ addVariant }) { - addVariant('magic', '@media screen and (max-width: 600px)') + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') }, ], } return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media screen and (max-width: 600px) { - .magic\:text-center { - text-align: center; - } - } - `) - }) - }) - - test('custom addVariant with nested media & format shorthand', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('magic', '@supports (hover: hover) { @media print { &:disabled } }') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @supports (hover: hover) { - @media print { - .magic\:text-center:disabled { - text-align: center; - } - } - } - `) - }) - }) - - test('before and after variants are a bit special, and forced to the end', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .before\:hover\:text-center:hover:before, - .hover\:before\:text-center:hover:before { - content: var(--tw-content); + :where(.prose-headings\:text-center) :is(h1, h2, h3, h4) { text-align: center; } `) }) }) - test('before and after variants are a bit special, and forced to the end (2)', () => { + test('prose-headings with another "simple" variant', () => { let config = { content: [ { raw: html` -
-
+
+
`, }, ], @@ -421,759 +96,1049 @@ crosscheck(({ stable, oxide }) => { return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - :where(.before\:prose-headings\:text-center) :is(h1, h2, h3, h4):before, - :where(.prose-headings\:before\:text-center) :is(h1, h2, h3, h4):before { - content: var(--tw-content); + :where(.hover\:prose-headings\:text-center) :is(h1, h2, h3, h4):hover, + :where(.prose-headings\:hover\:text-center:hover) :is(h1, h2, h3, h4) { text-align: center; } `) }) }) - test('returning non-strings and non-selectors in addVariant', () => { - /** @type {import('../types/config').Config} */ + test('prose-headings with another "complex" variant', () => { let config = { content: [ { raw: html` -
-
+
+
`, }, ], plugins: [ - function ({ addVariant, e }) { - addVariant('peer-aria-expanded', ({ modifySelectors, separator }) => - // Returning anything other string | string[] | undefined here is not supported - // But we're trying to be lenient here and just throw it out - modifySelectors( - ({ className }) => - `.peer[aria-expanded="true"] ~ .${e(`peer-aria-expanded${separator}${className}`)}` - ) - ) + function ({ addVariant }) { + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') + }, + ], + } - addVariant('peer-aria-expanded-2', ({ modifySelectors, separator }) => { - let nodes = modifySelectors( - ({ className }) => `.${e(`peer-aria-expanded-2${separator}${className}`)}` - ) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .group:hover :where(.group-hover\:prose-headings\:text-center) :is(h1, h2, h3, h4), + :where(.group:hover .prose-headings\:group-hover\:text-center) :is(h1, h2, h3, h4) { + text-align: center; + } + `) + }) + }) - return [ - // Returning anything other than strings here is not supported - // But we're trying to be lenient here and just throw it out - nodes, - '.peer[aria-expanded="false"] ~ &', - ] + test('using variants with multi-class selectors', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant, addComponents }) { + addComponents({ + '.parent .child': { + foo: 'bar', + }, }) + addVariant('screen', '@media screen') }, ], } return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .peer[aria-expanded='true'] ~ .peer-aria-expanded\:text-center, - .peer[aria-expanded='false'] ~ .peer-aria-expanded-2\:text-center { - text-align: center; + @media screen { + .screen\:parent .child, + .parent .screen\:child { + foo: bar; + } } `) }) }) - it('should not generate variants of user css if it is not inside a layer', () => { + test('using multiple classNames in your custom variant', () => { let config = { - content: [{ raw: html`
` }], - plugins: [], + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('my-variant', '&:where(.one, .two, .three)') + }, + ], } let input = css` @tailwind components; @tailwind utilities; - .foo { - color: red; + @layer components { + .test { + @apply my-variant:italic; + } } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .foo { - color: red; + .test:where(.one, .two, .three) { + font-style: italic; } - `) - }) - }) - - it('should be possible to use responsive modifiers that are defined with special characters', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - screens: { - ' { - return expect(result.css).toMatchFormattedCss(css` - @media (max-width: 399px) { - .\ { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - return expect(result.css).toMatchFormattedCss( - css` - ${defaults} - ` - ) - }) - }) - - it('variants for components should not be produced in a file without a components layer', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - it('variants for utilities should not be produced in a file without a utilities layer', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind components', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - `) - }) - }) - - test('The visited variant removes opacity support', () => { - let config = { - content: [ - { - raw: html` - Look, it's a link! - `, - }, - ], - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .visited\:border-red-500:visited { - border-color: #ef4444; - } - .visited\:bg-red-500:visited { - background-color: #ef4444; - } - .visited\:text-red-500:visited { - color: #ef4444; - } - `) - }) - }) - - it('appends variants to the correct place when using postcss documents', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - const doc = postcss.document() - doc.append(postcss.parse(`a {}`)) - doc.append(postcss.parse(`@tailwind base`)) - doc.append(postcss.parse(`@tailwind utilities`)) - doc.append(postcss.parse(`b {}`)) - - const result = doc.toResult() - - return run(result, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .underline { + .my-variant\:underline:where(.one, .two, .three) { text-decoration-line: underline; } - @media (min-width: 640px) { - .sm\:underline { - text-decoration-line: underline; - } - } `) }) }) - it('variants support multiple, grouped selectors (html)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .base1 .foo, - .base1 .bar { - color: red; - } - - .base2 .bar .base2-foo { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:base1 .foo, - .sm\:base1 .bar, - .sm\:base2 .bar .base2-foo { - color: red; - } - } - `) - }) - }) - - it('variants support multiple, grouped selectors (apply)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .base .foo, - .base .bar { - color: red; - } - } - .baz { - @apply sm:base; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .baz .foo, - .baz .bar { - color: red; - } - } - `) - }) - }) - - it('variants only picks the used selectors in a group (html)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .a, - .b { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:b { - color: red; - } - } - `) - }) - }) - - it('variants only picks the used selectors in a group (apply)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .a, - .b { - color: red; - } - } - .baz { - @apply sm:b; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .baz { - color: red; - } - } - `) - }) - }) - - test('hoverOnlyWhenSupported adds hover and pointer media features by default', () => { - let config = { - future: { - hoverOnlyWhenSupported: true, - }, - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (hover: hover) and (pointer: fine) { - .hover\:underline:hover, - .group:hover .group-hover\:underline, - .peer:hover ~ .peer-hover\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - test('multi-class utilities handle selector-mutating variants correctly', () => { + test('variant format string must include at-rule or & (1)', async () => { let config = { content: [ { - raw: html`
`, - }, - { - raw: html`
`, + raw: html`
`, }, ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .foo.bar.baz { - color: red; - } - .foo1 .bar1 .baz1 { - color: red; - } - } - ` - - // The second set of ::after cases (w/ descendant selectors) - // are clearly "wrong" BUT you can't have a descendant of a - // pseudo - element so the utilities `after:foo1` and - // `after:bar1` are non-sensical so this is still - // perfectly fine behavior - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .after\:foo.bar.baz:after, - .after\:bar.foo.baz:after, - .after\:baz.foo.bar:after, - .after\:foo1 .bar1 .baz1:after, - .foo1 .after\:bar1 .baz1:after, - .foo1 .bar1 .after\:baz1:after { - content: var(--tw-content); - color: red; - } - .hover\:foo:hover.bar.baz, - .hover\:bar:hover.foo.baz, - .hover\:baz:hover.foo.bar, - .hover\:foo1:hover .bar1 .baz1, - .foo1 .hover\:bar1:hover .baz1, - .foo1 .bar1 .hover\:baz1:hover, - .group:hover .group-hover\:foo.bar.baz, - .group:hover .group-hover\:bar.foo.baz, - .group:hover .group-hover\:baz.foo.bar, - .group:hover .group-hover\:foo1 .bar1 .baz1, - .foo1 .group:hover .group-hover\:bar1 .baz1, - .foo1 .bar1 .group:hover .group-hover\:baz1, - .peer:checked ~ .peer-checked\:foo.bar.baz, - .peer:checked ~ .peer-checked\:bar.foo.baz, - .peer:checked ~ .peer-checked\:baz.foo.bar, - .peer:checked ~ .peer-checked\:foo1 .bar1 .baz1, - .foo1 .peer:checked ~ .peer-checked\:bar1 .baz1, - .foo1 .bar1 .peer:checked ~ .peer-checked\:baz1 { - color: red; - } - `) - }) - }) - - test('class inside pseudo-class function :has', () => { - let config = { - content: [ - { raw: html`
` }, - { raw: html`
` }, - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - :where(.foo) { - color: red; - } - :is(.foo, .bar, .baz) { - color: orange; - } - :is(.foo) { - color: yellow; - } - html:has(.foo) { - color: green; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :where(.foo) { - color: red; - } - :is(.foo, .bar, .baz) { - color: orange; - } - .foo { - color: #ff0; - } - html:has(.foo) { - color: green; - } - :where(.hover\:foo:hover) { - color: red; - } - :is(.hover\:foo:hover, .bar, .baz), - :is(.foo, .hover\:bar:hover, .baz), - :is(.foo, .bar, .hover\:baz:hover) { - color: orange; - } - .hover\:foo:hover { - color: #ff0; - } - html:has(.hover\:foo:hover) { - color: green; - } - @media (min-width: 640px) { - :where(.sm\:foo) { - color: red; - } - :is(.sm\:foo, .bar, .baz), - :is(.foo, .sm\:bar, .baz), - :is(.foo, .bar, .sm\:baz) { - color: orange; - } - .sm\:foo { - color: #ff0; - } - html:has(.sm\:foo) { - color: green; - } - } - `) - }) - }) - - test('variant functions returning arrays should output correct results when nesting', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, plugins: [ - function ({ addUtilities, addVariant }) { - addVariant('test', () => ['@media (test)']) - addUtilities({ - '.foo': { - display: 'grid', - '> *': { - 'grid-column': 'span 2', - }, - }, - }) + function ({ addVariant }) { + addVariant('wtf-bbq', 'lol') }, ], } - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - @media (test) { - .test\:foo { - display: grid; - } - .test\:foo > * { - grid-column: span 2; - } - } - `) + await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( + "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." + ) }) - test('variants with slashes in them work', () => { + test('variant format string must include at-rule or & (2)', async () => { let config = { content: [ { - raw: html`
ar-1/10
`, + raw: html`
`, }, ], - theme: { - extend: { - screens: { - 'ar-1/10': { raw: '(min-aspect-ratio: 1/10)' }, - }, - }, - }, - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) { - .ar-1\/10\:text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) { - .ar-1\/10\:text-red-500 { - color: #ef4444; - } - } - `) - }) - }) - - test('variants with slashes support modifiers', () => { - let config = { - content: [ - { - raw: html`
ar-1/10
`, - }, - ], - corePlugins: { preflight: false }, plugins: [ - function ({ matchVariant }) { - matchVariant( - 'ar', - (value, { modifier }) => { - return [`@media (min-aspect-ratio: ${value}) and (foo: ${modifier})`] - }, - { values: { '1/10': '1/10' } } - ) + function ({ addVariant }) { + addVariant('wtf-bbq', () => 'lol') }, ], } - let input = css` - @tailwind utilities; - ` + await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( + "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." + ) + }) +}) - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) and (foo: 20) { - .ar-1\/10\/20\:text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - } +test('stacked peer variants', async () => { + let config = { + content: [{ raw: 'peer-disabled:peer-focus:peer-hover:flex' }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + let result = await run(input, config) + expect(result.css).toIncludeCss(css` + .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex { + display: flex; + } + `) +}) + +it('should properly handle keyframes with multiple variants', async () => { + let config = { + content: [ + { + raw: 'animate-spin hover:animate-spin focus:animate-spin hover:animate-bounce focus:animate-bounce', + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + ` + + let result = await run(input, config) + expect(result.css).toMatchFormattedCss(css` + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .animate-spin { + animation: 1s linear infinite spin; + } + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); + } + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; + } + } + .hover\:animate-bounce:hover { + animation: 1s infinite bounce; + } + .hover\:animate-spin:hover { + animation: 1s linear infinite spin; + } + .focus\:animate-bounce:focus { + animation: 1s infinite bounce; + } + .focus\:animate-spin:focus { + animation: 1s linear infinite spin; + } + `) +}) + +test('custom addVariant with more complex media query params', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('magic', '@media screen and (max-width: 600px)') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media screen and (max-width: 600px) { + .magic\:text-center { + text-align: center; } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) and (foo: 20) { - .ar-1\/10\/20\:text-red-500 { - color: #ef4444; - } - } - `) - }) - }) - - test('arbitrary variant selectors should not re-order scrollbar pseudo classes', async () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .\[\&\:\:-webkit-resizer\:hover\]\:underline::-webkit-resizer:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-button\:hover\]\:underline::-webkit-scrollbar-button:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-corner\:hover\]\:underline::-webkit-scrollbar-corner:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:underline::-webkit-scrollbar-thumb:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-track-piece\:hover\]\:underline::-webkit-scrollbar-track-piece:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-track\:hover\]\:underline::-webkit-scrollbar-track:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar\:hover\]\:underline::-webkit-scrollbar:hover { - text-decoration-line: underline; - } - `) - }) - - test('stacking dark and rtl variants', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { - font-style: italic; - } - `) - }) - - test('stacking dark and rtl variants with pseudo elements', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:placeholder\:italic))::placeholder { - font-style: italic; } `) }) }) + +test('custom addVariant with nested media & format shorthand', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('magic', '@supports (hover: hover) { @media print { &:disabled } }') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @supports (hover: hover) { + @media print { + .magic\:text-center:disabled { + text-align: center; + } + } + } + `) + }) +}) + +test('before and after variants are a bit special, and forced to the end', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .before\:hover\:text-center:hover:before, + .hover\:before\:text-center:hover:before { + content: var(--tw-content); + text-align: center; + } + `) + }) +}) + +test('before and after variants are a bit special, and forced to the end (2)', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :where(.before\:prose-headings\:text-center) :is(h1, h2, h3, h4):before, + :where(.prose-headings\:before\:text-center) :is(h1, h2, h3, h4):before { + content: var(--tw-content); + text-align: center; + } + `) + }) +}) + +test('returning non-strings and non-selectors in addVariant', () => { + /** @type {import('../types/config').Config} */ + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [ + function ({ addVariant, e }) { + addVariant('peer-aria-expanded', ({ modifySelectors, separator }) => + // Returning anything other string | string[] | undefined here is not supported + // But we're trying to be lenient here and just throw it out + modifySelectors( + ({ className }) => + `.peer[aria-expanded="true"] ~ .${e(`peer-aria-expanded${separator}${className}`)}` + ) + ) + + addVariant('peer-aria-expanded-2', ({ modifySelectors, separator }) => { + let nodes = modifySelectors( + ({ className }) => `.${e(`peer-aria-expanded-2${separator}${className}`)}` + ) + + return [ + // Returning anything other than strings here is not supported + // But we're trying to be lenient here and just throw it out + nodes, + '.peer[aria-expanded="false"] ~ &', + ] + }) + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .peer[aria-expanded='true'] ~ .peer-aria-expanded\:text-center, + .peer[aria-expanded='false'] ~ .peer-aria-expanded-2\:text-center { + text-align: center; + } + `) + }) +}) + +it('should not generate variants of user css if it is not inside a layer', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo { + color: red; + } + `) + }) +}) + +it('should be possible to use responsive modifiers that are defined with special characters', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + ' { + return expect(result.css).toMatchFormattedCss(css` + @media (max-width: 399px) { + .\ { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + return expect(result.css).toMatchFormattedCss( + css` + ${defaults} + ` + ) + }) +}) + +it('variants for components should not be produced in a file without a components layer', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +it('variants for utilities should not be produced in a file without a utilities layer', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind components', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:container { + width: 100%; + } + @media (min-width: 640px) { + .sm\:container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .sm\:container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .sm\:container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .sm\:container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .sm\:container { + max-width: 1536px; + } + } + } + `) + }) +}) + +test('The visited variant removes opacity support', () => { + let config = { + content: [ + { + raw: html` + Look, it's a link! + `, + }, + ], + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .visited\:border-red-500:visited { + border-color: #ef4444; + } + .visited\:bg-red-500:visited { + background-color: #ef4444; + } + .visited\:text-red-500:visited { + color: #ef4444; + } + `) + }) +}) + +it('appends variants to the correct place when using postcss documents', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + const doc = postcss.document() + doc.append(postcss.parse(`a {}`)) + doc.append(postcss.parse(`@tailwind base`)) + doc.append(postcss.parse(`@tailwind utilities`)) + doc.append(postcss.parse(`b {}`)) + + const result = doc.toResult() + + return run(result, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .underline { + text-decoration-line: underline; + } + @media (min-width: 640px) { + .sm\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +it('variants support multiple, grouped selectors (html)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .base1 .foo, + .base1 .bar { + color: red; + } + + .base2 .bar .base2-foo { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:base1 .foo, + .sm\:base1 .bar, + .sm\:base2 .bar .base2-foo { + color: red; + } + } + `) + }) +}) + +it('variants support multiple, grouped selectors (apply)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .base .foo, + .base .bar { + color: red; + } + } + .baz { + @apply sm:base; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .baz .foo, + .baz .bar { + color: red; + } + } + `) + }) +}) + +it('variants only picks the used selectors in a group (html)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:b { + color: red; + } + } + `) + }) +}) + +it('variants only picks the used selectors in a group (apply)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + color: red; + } + } + .baz { + @apply sm:b; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .baz { + color: red; + } + } + `) + }) +}) + +test('hoverOnlyWhenSupported adds hover and pointer media features by default', () => { + let config = { + future: { + hoverOnlyWhenSupported: true, + }, + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (hover: hover) and (pointer: fine) { + .hover\:underline:hover, + .group:hover .group-hover\:underline, + .peer:hover ~ .peer-hover\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +test('multi-class utilities handle selector-mutating variants correctly', () => { + let config = { + content: [ + { + raw: html`
`, + }, + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .foo.bar.baz { + color: red; + } + .foo1 .bar1 .baz1 { + color: red; + } + } + ` + + // The second set of ::after cases (w/ descendant selectors) + // are clearly "wrong" BUT you can't have a descendant of a + // pseudo - element so the utilities `after:foo1` and + // `after:bar1` are non-sensical so this is still + // perfectly fine behavior + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .after\:foo.bar.baz:after, + .after\:bar.foo.baz:after, + .after\:baz.foo.bar:after, + .after\:foo1 .bar1 .baz1:after, + .foo1 .after\:bar1 .baz1:after, + .foo1 .bar1 .after\:baz1:after { + content: var(--tw-content); + color: red; + } + .hover\:foo:hover.bar.baz, + .hover\:bar:hover.foo.baz, + .hover\:baz:hover.foo.bar, + .hover\:foo1:hover .bar1 .baz1, + .foo1 .hover\:bar1:hover .baz1, + .foo1 .bar1 .hover\:baz1:hover, + .group:hover .group-hover\:foo.bar.baz, + .group:hover .group-hover\:bar.foo.baz, + .group:hover .group-hover\:baz.foo.bar, + .group:hover .group-hover\:foo1 .bar1 .baz1, + .foo1 .group:hover .group-hover\:bar1 .baz1, + .foo1 .bar1 .group:hover .group-hover\:baz1, + .peer:checked ~ .peer-checked\:foo.bar.baz, + .peer:checked ~ .peer-checked\:bar.foo.baz, + .peer:checked ~ .peer-checked\:baz.foo.bar, + .peer:checked ~ .peer-checked\:foo1 .bar1 .baz1, + .foo1 .peer:checked ~ .peer-checked\:bar1 .baz1, + .foo1 .bar1 .peer:checked ~ .peer-checked\:baz1 { + color: red; + } + `) + }) +}) + +test('class inside pseudo-class function :has', () => { + let config = { + content: [ + { raw: html`
` }, + { raw: html`
` }, + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + :where(.foo) { + color: red; + } + :is(.foo, .bar, .baz) { + color: orange; + } + :is(.foo) { + color: yellow; + } + html:has(.foo) { + color: green; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :where(.foo) { + color: red; + } + :is(.foo, .bar, .baz) { + color: orange; + } + .foo { + color: #ff0; + } + html:has(.foo) { + color: green; + } + :where(.hover\:foo:hover) { + color: red; + } + :is(.hover\:foo:hover, .bar, .baz), + :is(.foo, .hover\:bar:hover, .baz), + :is(.foo, .bar, .hover\:baz:hover) { + color: orange; + } + .hover\:foo:hover { + color: #ff0; + } + html:has(.hover\:foo:hover) { + color: green; + } + @media (min-width: 640px) { + :where(.sm\:foo) { + color: red; + } + :is(.sm\:foo, .bar, .baz), + :is(.foo, .sm\:bar, .baz), + :is(.foo, .bar, .sm\:baz) { + color: orange; + } + .sm\:foo { + color: #ff0; + } + html:has(.sm\:foo) { + color: green; + } + } + `) + }) +}) + +test('variant functions returning arrays should output correct results when nesting', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ addUtilities, addVariant }) { + addVariant('test', () => ['@media (test)']) + addUtilities({ + '.foo': { + display: 'grid', + '> *': { + 'grid-column': 'span 2', + }, + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + @media (test) { + .test\:foo { + display: grid; + } + .test\:foo > * { + grid-column: span 2; + } + } + `) +}) + +test('variants with slashes in them work', () => { + let config = { + content: [ + { + raw: html`
ar-1/10
`, + }, + ], + theme: { + extend: { + screens: { + 'ar-1/10': { raw: '(min-aspect-ratio: 1/10)' }, + }, + }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-aspect-ratio: 1 / 10) { + .ar-1\/10\:flex { + display: flex; + } + } + `) + }) +}) + +test('variants with slashes support modifiers', () => { + let config = { + content: [ + { + raw: html`
ar-1/10
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ matchVariant }) { + matchVariant( + 'ar', + (value, { modifier }) => { + return [`@media (min-aspect-ratio: ${value}) and (foo: ${modifier})`] + }, + { values: { '1/10': '1/10' } } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-aspect-ratio: 1 / 10) and (foo: 20) { + .ar-1\/10\/20\:flex { + display: flex; + } + } + `) + }) +}) + +test('arbitrary variant selectors should not re-order scrollbar pseudo classes', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .\[\&\:\:-webkit-resizer\:hover\]\:underline::-webkit-resizer:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-button\:hover\]\:underline::-webkit-scrollbar-button:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-corner\:hover\]\:underline::-webkit-scrollbar-corner:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:underline::-webkit-scrollbar-thumb:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-track-piece\:hover\]\:underline::-webkit-scrollbar-track-piece:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-track\:hover\]\:underline::-webkit-scrollbar-track:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar\:hover\]\:underline::-webkit-scrollbar:hover { + text-decoration-line: underline; + } + `) +}) + +test('stacking dark and rtl variants', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { + font-style: italic; + } + `) +}) + +test('stacking dark and rtl variants with pseudo elements', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + :is(.dark :is([dir='rtl'] .dark\:rtl\:placeholder\:italic))::placeholder { + font-style: italic; + } + `) +}) diff --git a/tests/warnings.test.js b/tests/warnings.test.js index e3ea94fe5..d74f1dd52 100644 --- a/tests/warnings.test.js +++ b/tests/warnings.test.js @@ -1,62 +1,61 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('it warns when there is no content key', async () => { - let config = { - corePlugins: { preflight: false }, - } +test('it warns when there is no content key', async () => { + let config = { + presets: [], // Prevents the default config from being merged in and therefore `content: ['auto']` is not used. + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - ` + let input = css` + @tailwind base; + ` - await run(input, config) + await run(input, config) - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - test('it warns when there is an empty content key', async () => { - let config = { - content: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - ` - - await run(input, config) - - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - test('it warns when there are no utilities generated', async () => { - let config = { - content: [{ raw: html`nothing here matching a utility` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - it('warnings are not thrown when only variant utilities are generated', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - expect().not.toHaveBeenWarned() - }) + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +test('it warns when there is an empty content key', async () => { + let config = { + content: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + ` + + await run(input, config) + + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +test('it warns when there are no utilities generated', async () => { + let config = { + content: [{ raw: html`nothing here matching a utility` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +it('warnings are not thrown when only variant utilities are generated', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + expect().not.toHaveBeenWarned() }) diff --git a/tests/withAlphaVariable.test.js b/tests/withAlphaVariable.test.js index 29d39c7aa..d543dfc6e 100644 --- a/tests/withAlphaVariable.test.js +++ b/tests/withAlphaVariable.test.js @@ -1,243 +1,240 @@ import withAlphaVariable from '../src/util/withAlphaVariable' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it adds the right custom property', () => { - expect( - withAlphaVariable({ color: '#ff0000', property: 'color', variable: '--tw-text-opacity' }) - ).toEqual({ - '--tw-text-opacity': '1', - color: 'rgb(255 0 0 / var(--tw-text-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(240 100% 50%)', - property: 'color', - variable: '--tw-text-opacity', - }) - ).toEqual({ - '--tw-text-opacity': '1', - color: 'hsl(240 100% 50% / var(--tw-text-opacity))', - }) +test('it adds the right custom property', () => { + expect( + withAlphaVariable({ color: '#ff0000', property: 'color', variable: '--tw-text-opacity' }) + ).toEqual({ + '--tw-text-opacity': '1', + color: 'rgb(255 0 0 / var(--tw-text-opacity))', }) - - test('it ignores colors that cannot be parsed', () => { - expect( - withAlphaVariable({ - color: 'currentColor', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'currentColor', - }) - expect( - withAlphaVariable({ - color: 'rgb(255, 0)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255, 0)', - }) - expect( - withAlphaVariable({ - color: 'rgb(255)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255)', - }) - expect( - withAlphaVariable({ - color: 'rgb(255, 0, 0, 255)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255, 0, 0, 255)', - }) - expect( - withAlphaVariable({ - color: 'rgb(var(--color))', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(var(--color))', - }) - }) - - test('it ignores colors that already have an alpha channel', () => { - expect( - withAlphaVariable({ - color: '#ff0000ff', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#ff0000ff', - }) - expect( - withAlphaVariable({ - color: '#ff000080', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#ff000080', - }) - expect( - withAlphaVariable({ - color: '#f00a', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#f00a', - }) - expect( - withAlphaVariable({ - color: '#f00f', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#f00f', - }) - expect( - withAlphaVariable({ - color: 'rgba(255, 255, 255, 1)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255, 255, 255, 1)', - }) - expect( - withAlphaVariable({ - color: 'rgba(255, 255, 255, 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255, 255, 255, 0.5)', - }) - expect( - withAlphaVariable({ - color: 'rgba(255 255 255 / 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255 255 255 / 0.5)', - }) - expect( - withAlphaVariable({ - color: 'hsla(240, 100%, 50%, 1)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsla(240, 100%, 50%, 1)', - }) - expect( - withAlphaVariable({ - color: 'hsla(240, 100%, 50%, 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsla(240, 100%, 50%, 0.5)', - }) - expect( - withAlphaVariable({ - color: 'hsl(240 100% 50% / 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsl(240 100% 50% / 0.5)', - }) - }) - - test('it allows a closure to be passed', () => { - expect( - withAlphaVariable({ - color: ({ opacityVariable }) => `rgba(0, 0, 0, var(${opacityVariable}))`, - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: ({ opacityValue }) => `rgba(0, 0, 0, ${opacityValue})`, - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', - }) - }) - - test('it transforms rgb and hsl to space-separated rgb and hsl', () => { - expect( - withAlphaVariable({ - color: 'rgb(50, 50, 50)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'rgb(50 50 50)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(50, 50%, 50%)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(50 50% 50%)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', - }) - }) - - test('it transforms named colors to rgb', () => { - expect( - withAlphaVariable({ - color: 'red', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(255 0 0 / var(--tw-bg-opacity))', + expect( + withAlphaVariable({ + color: 'hsl(240 100% 50%)', + property: 'color', + variable: '--tw-text-opacity', }) + ).toEqual({ + '--tw-text-opacity': '1', + color: 'hsl(240 100% 50% / var(--tw-text-opacity))', + }) +}) + +test('it ignores colors that cannot be parsed', () => { + expect( + withAlphaVariable({ + color: 'currentColor', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'currentColor', + }) + expect( + withAlphaVariable({ + color: 'rgb(255, 0)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255, 0)', + }) + expect( + withAlphaVariable({ + color: 'rgb(255)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255)', + }) + expect( + withAlphaVariable({ + color: 'rgb(255, 0, 0, 255)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255, 0, 0, 255)', + }) + expect( + withAlphaVariable({ + color: 'rgb(var(--color))', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(var(--color))', + }) +}) + +test('it ignores colors that already have an alpha channel', () => { + expect( + withAlphaVariable({ + color: '#ff0000ff', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#ff0000ff', + }) + expect( + withAlphaVariable({ + color: '#ff000080', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#ff000080', + }) + expect( + withAlphaVariable({ + color: '#f00a', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#f00a', + }) + expect( + withAlphaVariable({ + color: '#f00f', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#f00f', + }) + expect( + withAlphaVariable({ + color: 'rgba(255, 255, 255, 1)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255, 255, 255, 1)', + }) + expect( + withAlphaVariable({ + color: 'rgba(255, 255, 255, 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255, 255, 255, 0.5)', + }) + expect( + withAlphaVariable({ + color: 'rgba(255 255 255 / 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255 255 255 / 0.5)', + }) + expect( + withAlphaVariable({ + color: 'hsla(240, 100%, 50%, 1)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsla(240, 100%, 50%, 1)', + }) + expect( + withAlphaVariable({ + color: 'hsla(240, 100%, 50%, 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsla(240, 100%, 50%, 0.5)', + }) + expect( + withAlphaVariable({ + color: 'hsl(240 100% 50% / 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsl(240 100% 50% / 0.5)', + }) +}) + +test('it allows a closure to be passed', () => { + expect( + withAlphaVariable({ + color: ({ opacityVariable }) => `rgba(0, 0, 0, var(${opacityVariable}))`, + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: ({ opacityValue }) => `rgba(0, 0, 0, ${opacityValue})`, + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', + }) +}) + +test('it transforms rgb and hsl to space-separated rgb and hsl', () => { + expect( + withAlphaVariable({ + color: 'rgb(50, 50, 50)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'rgb(50 50 50)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'hsl(50, 50%, 50%)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'hsl(50 50% 50%)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', + }) +}) + +test('it transforms named colors to rgb', () => { + expect( + withAlphaVariable({ + color: 'red', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(255 0 0 / var(--tw-bg-opacity))', }) }) diff --git a/turbo.json b/turbo.json index ef1c9043d..8ddd398f5 100644 --- a/turbo.json +++ b/turbo.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "pipeline": { "//#build": { - "outputs": ["lib/**", "peers/**", "types/generated/**"], + "outputs": ["lib/**", "types/generated/**"], "inputs": ["src/**", "oxide/**", "nesting/**", "oxide-node-api-shim/**", "types/**"] }, "test": { diff --git a/types/config.d.ts b/types/config.d.ts index bb40c8b71..98ce44a6a 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -60,10 +60,11 @@ type FutureConfigValues = | 'respectDefaultRingColorOpacity' | 'disableColorOpacityUtilitiesByDefault' | 'relativeContentPathsByDefault' + | 'logicalSiblingUtilities' type FutureConfig = Expand<'all' | Partial>> | [] // Experimental related config -type ExperimentalConfigValues = 'optimizeUniversalDefaults' | 'matchVariant' +type ExperimentalConfigValues = 'optimizeUniversalDefaults' | 'oxideParser' type ExperimentalConfig = Expand<'all' | Partial>> | [] // DarkMode related config